ドラゴンクエストシリーズ第一作目に登場する「ふっかつのじゅもん」っぽいBase64亜種を書いてみました。
shogo82148/base64dq 使い方 簡単に使えるようコマンドラインインターフェイスも用意しました。go installでインストール可能です。
$ go install github.com/shogo82148/base64dq/cmd/base64dq@latest base64dqコマンドが使えるようになります。 Coreutilsのbase64コマンドと同様に使えます。
$ echo 'こんにちは' | base64dq づづきとづづさとづづきわづづきめづづきげうむ・・ $ echo 'づづきとづづさとづづきわづづきめづづきげうむ・・' | base64dq --decode こんにちは ふっかつのじゅもん 「ふっかつのじゅもん」はドラゴンクエストシリーズ第一作目で採用されたゲームのセーブ方式です。 ゲームを中断するときには、再開したときに同じ状態からゲームを始められるよう、ゲームの状態を保存しておく必要があります。 しかしドラクエIが発売されたのは1986年5月。 当時ドラクエIはファミコン向けに発売されたのですが、ファミコンにはフラッシュROMのような贅沢なハードウェアはついていません。 電源を落とすと簡単にデーターは失われてしまいます。
そこでゲームの状態を20文字の「ふっかつのじゅもん」にエンコードし、 再開時には「ふっかつのじゅもん」をプレイヤーに入力してもらう、というセーブ方式が編み出されました。
プレイヤーはゲームを中断するたびに「ふっかつのじゅもん」を書き写す必要がありました。 当時は液晶ディスプレイなどあるはずもなく、一般の家庭にあるのはブラウン管のアナログディスプレイです。 解像度が荒く読み取るのが大変なため、「ふっかつのじゅもん」を間違え散っていったプレイヤーも多くいたと聞いています(筆者はまだ生まれていないのでよく知らない)。
ふっかつのじゅもんとBase64の関係 今では有志による解読も進みふっかつのじゅもんのジェネレーターも開発されています。
DQ1 復活の呪文解析日記によると、「ふっかつのじゅもん」は64種類のひらがなで構成されているそうです。 64。実に切りのいい数字です。 1文字で6ビットの情報を表し、合計で120ビットのセーブデータを表現しています。
このエンコード方法はBase64とまったく同じですね! 「ふっかつのじゅもん」は、64種類のASCII文字の代わりに、64種類のひらがなを使ったBase64の亜種、と考えることができます。
ちなみにBase64がRFCに登場したのは1987年4月のRFC 989だそうです。 当時はBase64という言葉すらなく、printable encodingと呼ばれていたようです。 ドラクエIが発売されたのは1986年5月なので、Base64が一般に広まる前に「ふっかつのじゅもん」は世に公開されたわけですね。 すごい!
もちろん規格化されていないだけで「64種類の文字で情報をエンコードする」というアイディア自体はもっと昔からあったのでしょう。 でも似たようなものがゲームに使われていたのはおもしろいですね。
base64dq そういうわけで「ふっかつのじゅもん」の影響を受けて作ったのが shogo82148/base64dq です。 64種類のASCII文字の代わりに、以下の64種類のひらがなを使います。
あいうえお かきくけこ さしすせそ たちつてと なにぬねの はひふへほ まみむめも やゆよ らりるれろ わ がぎぐげご ざじずぜぞ だぢづでど ばびぶべぼ ・(パディング) 「ふっかつのじゅもん」にはパディングはないので、適当に「・」を選びました。
GitHubのプロジェクトを見に行くと、サイドバーに「Used by(数字)」と書かれたセクションがあります。
これの設定方法を知ったのでメモ。
TL;DR レポジトリのナビゲーションバーから「Setting」をクリックし設定画面を開きます サイドバーから「Code security and analysis」を選択します 「Used by counter」という項目で、たくさん使ってもらっていそうなパッケージを選択します 背景 GitHub Actions上でFuzzingを実行するアクションを書いたでshogo82148/actions-go-fuzzというGitHub Actionを作りました。 このために作ったレポジトリの概要を眺めていると、いつの間にか「Used by 3」という表示が増えてました。 これ自体はおかしなことではありません。お試しで自分が過去に作ったレポジトリにshogo82148/actions-go-fuzzを導入したので、依存しているレポジトリは存在します。
ずっと不思議だったのは、自分の作った他のGitHub Actionにはこの表示がないこと。 たとえば「actions-setup-perl」でGitHubを検索すると、それなりに使用例が出てきます。 しかし、shogo82148/actions-setup-perlには(この文章を書く前の時点では)「Used by(数字)」のセクションはありませんでした。
原因 ただの趣味でやっているので別に利用者がいなくたって構わないんですが、 やっぱり利用者がいるとモチベーションが変わってくるじゃないですか。 そういうわけで、表示方法を探したところ公式ドキュメントにたどり着きました。
Changing the “Used by” package ドキュメントによると、ひとつのレポジトリで複数のパッケージを提供していると、 このようなことが起こるそうです。
shogo82148/actions-setup-perlの場合、GitHubの依存解析によって「JavaScriptのパッケージ」「GitHub Actionのパッケージ」の2つが検出されました。 shogo82148/actions-setup-perlはTypeScriptで実装されているので「JavaScriptのパッケージ」として認識されるのは仕方のないことです。 しかし、利用者はみんなGitHub Actionとして利用するので、実際に「JavaScriptのパッケージ」として利用する人はいません。 というかそういう使い方は想定していないので、使われていないのは正しい。 利用者がいないので、「Used by(数字)」の表示がなかったんですね。
ドキュメントに記載されている通り、「Used by counter」の設定を変更すれば無事表示されます。 shogo82148/actions-setup-perlも「GitHub Actionのパッケージ」としてカウントされるよう設定を変更したので、 この記事を書いている時点では利用者数が表示されるようになりました。
まとめ GitHubのレポジトリで利用者数が表示されるアレは「Used by counter」という名前らしい 設定の「Code security and analysis」から変更できるよ 個人的に「Code security and analysis」から変更できるというのは盲点でした。 「security」の文字だけ見て「セキュリティー関連の設定かー」と思っていたんですが、 なるほど「Code analysis(コード分析)」の設定も含まれているんですね。
レポジトリの設定多すぎて覚えきれないよ・・・。
参考 Changing the “Used by” package GitHub Actions上でFuzzingを実行するアクションを書いた shogo82148/actions-setup-perl
Go 1.18からGo Fuzzingの機能が追加されました。 僕もいくつかのパッケージに導入してみたのですが、予期していなかったテストパターンを見つけられて役にやっている気がします。 Fuzzテストが増えてきたので、毎回手元でFuzzテストを実行するのも大変になってきました。
簡単にFuzzテストを実行する環境を作れないかと、GitHub Actions上でFuzzテストを実行するActionを書いてみました。
shogo82148/actions-go-fuzz 使い方 Fuzzingのチュートリアルのコードで試してみましょう。
テスト対象の関数を書く main.go に文字列を反転させるコードを書きます。
// main.go package main func Reverse(s string) string { b := []byte(s) for i, j := 0, len(b)-1; i < len(b)/2; i, j = i+1, j-1 { b[i], b[j] = b[j], b[i] } return string(b) } チュートリアルを進めていくとわかるのですが、このコードは「マルチバイト文字を正しく処理できない」というバグがあります。 このバグをFuzzingを使って見つけてもらいましょう。
Fuzzテストを書く Reverseを2回実行すると同じ文字列に戻るはずです。 このことを確認するテストを書きます。
さらに、入力がUTF-8としてValidであるなら、出力もValidであって欲しいです。 これもテストで確認します。
package main func FuzzReverse(f *testing.F) { testcases := []string{"Hello, world", " ", "!12345"} for _, tc := range testcases { f.
GitHub Actionsの利用量をまとめるではGitHub Actionsの使用量をGoogle Spreadsheetにまとめるスクリプトを書きました。 このときは動作確認ができればよかったので、自分のGoogleアカウントで認証して書き込みを行いました。 しかし、このスクリプトを定期的に実行するのも面倒です。
そこでGitHub Actionsのスケジュール実行機能を使い、毎日使用量を記録する設定を行いました。 イマドキAPIキーを使うのはリスクが高いので、Google CloudのWorkload Identity連携を使ってアクセスします。
Workload Identity 連携の構成 GitHub Actions からのキーなしの認証の有効化を参考にGoogle Cloud側の設定を行います。 設定内容をバージョン管理したいので、設定にはTerraformを使用します。 意外と作成するリソースが多くて大変なので、GitHub OIDC Terraform ModuleとProject API Activation Terraform Moduleを利用してみましょう。
provider "google" { batching { enable_batching = false } } # Google Cloudのプロジェクト resource "google_project" "my_project" { name = "my-project" project_id = "my-project" } # サービスアカウント resource "google_service_account" "github_actions" { project = google_project.my_project.id account_id = "github-actions" } # サービスAPIの有効化設定 module "project_services" { source = "terraform-google-modules/project-factory/google//modules/project_services" version = "14.
dependabot の更新グループ化(Grouped version updates)機能がパブリックベータになりました。
Grouped version updates for Dependabot public beta AWS SDK for Go v2の更新設定をしてみたのでメモ。
設定内容 グループ化したい依存をgroupsに設定します。 AWS SDK for Go v2関連のバージョンアップを、aws-sdkという名前でプルリクエストを出すよう設定しました。
updates: - package-ecosystem: gomod directory: "/" schedule: interval: daily groups: # AWS SDK for Go v2 関連のバージョンアップをまとめる aws-sdk: patterns: - github.com/aws/aws-sdk-go-v2 # `*` が空文字にマッチするのかよく分からなかったので・・・ - github.com/aws/aws-sdk-go-v2/* AWS SDK for Go v2 アップデートの困りごと AWS ではたくさんのサービスが公開されているので、毎日のようにサービスのアップデートが入り、 それに合わせて AWS SDK の更新が入ります。 dependabot のような自動アップデートの仕組みを入れておくと、本当に毎日のようにプルリクエストが来るのでとても大変です。 しかし、実際使う AWS のサービスなんて、全体に比べればほんの一部です。 ほとんどが自分の使っているサービスとは無関係な更新で、dependabot が送ってくるプルリクエストのほとんどはムダなものです。
AWS SDK for Go は v2 からマルチモジュール構成になり、サービス毎に go.
GitHub Actionsの利用量はsettings/billingから確認できます。
それはいいんですが、問題は今月分しか確認できないこと!
「先月は〇〇分使ったから上限いくらに設定しておくか〜〜」ということができません。 APIは見つけたので、取得スクリプトを組んでみました。
Get GitHub Actions billing for an organization 集計スクリプト GitHub REST APIをたたいて、結果をGoogle Spreadsheetにまとめます。 GitHub REST APIを叩く部分はGitHub CLIを使えばすぐにできるんですが、 Google Spreadsheetへの書き込みをシェルスクリプトで組むのはちょっと大変です。
今回はGoで書いてみました。
package main import ( "context" "encoding/json" "fmt" "io" "log" "net/http" "os" "time" "google.golang.org/api/sheets/v4" ) func main() { ctx := context.Background() token := os.Getenv("GITHUB_TOKEN") if token == "" { log.Fatal("GITHUB_TOKEN is required") } sheetID := os.Getenv("SHEET_ID") if sheetID == "" { log.Fatal("SHEET_ID is required") } org := os.
Go 1.21 Release Candidateで、 forループ変数のセマンティクス変更の予定をしりました。 導入の背景や影響について、WikiのLoopvarExperimentで説明されています。
地味にインパクトが大きそうだったので、内容を理解するために和訳しました。 といっても訳の大半はChatGPT ChatGPT May 24 Versionのものです。便利。 多少僕の修正も入ってます。
以下LoopvarExperimentのリビジョンdce06fbの和訳です。
Go 1.22では、Goチームはforループ変数のセマンティクスを変更し、繰り返し毎のクロージャやゴルーチンにおける意図しない共有を防止することを検討しています。 Go 1.21には、この変更の予備的な実装が含まれており、プログラムをビルドする際にGOEXPERIMENT=loopvarを設定することで有効になります。 変更の影響を理解するのに協力していただける方々には、GOEXPERIMENT=loopvarを使用して試してみていただき、遭遇した問題や成功した点についてご報告いただけると幸いです。
このページでは、変更に関するよくある質問にお答えします。
この変更を試すにはどうすればいいですか? Go 1.21を使用して、以下のようにGOEXPERIMENT=loopvarを設定してプログラムをビルドします。
GOEXPERIMENT=loopvar go install my/program GOEXPERIMENT=loopvar go build my/program GOEXPERIMENT=loopvar go test my/program GOEXPERIMENT=loopvar go test my/program -bench=. ... この問題はどのようなものですか? 以下のようなループを考えてみましょう:
func TestAllEvenBuggy(t *testing.T) { testCases := []int{1, 2, 4, 6} for _, v := range testCases { t.Run("sub", func(t *testing.T) { t.Parallel() if v&1 != 0 { t.
lestrrat-go/jwxに脆弱性を発見したので報告しました。
GHSA-rm8v-mxj3-5rmq Potential Padding Oracle Attack Vulnerability 「メールでやり取りするの面倒だなー」と思っていたら、いつのまにかGitHub経由で脆弱性報告できるようになってるじゃないですか。
Privately reporting a security vulnerability というわけで試してみたお話です。
背景 脆弱性報告の難しさ 脆弱性に関する情報は悪い人に悪用される可能性があるので、GitHubのIssueで報告するのは厳禁です。 公開レポジトリのIssueは広く公開されているので、悪い人に見つかってしまいます。
そのため、基本的に脆弱性の報告者はメンテナーと直接やり取りをする必要があります。 しかし、やり取りの方法に決まったルールはありません。 GitHubではセキュリティーポリシーをSECURITY.mdに記載するルールになっているので、運が良ければSECURITY.mdに連絡先が書いてあります。
Adding a security policy to your repository 運が悪ければ連絡先を頑張って探すところからはじめなければなりません。
まあ、たいていは連絡先としてメールアドレスが見つかるので、そこにメールを送ることになります。 ただし、メールというものは脆弱性の報告に特化したものではないので、どうやって情報をやり取りするかお互いに工夫が必要です。 僕はやったことないですが、修正のパッチをメーリングリストに送るんですかね。 大変そうです。
脆弱性と聞けば、CVEのような脆弱性情報データベースや、IPAの脆弱性関連情報の届出受付を思い浮かべるひとも多いでしょう。
共通脆弱性識別子CVE概説 - IPA 魚拓 脆弱性関連情報の届出受付 - IPA 魚拓 しかしこういった制度も、メンテナーの連絡先を管理しているわけではありません。 メンテナーの連絡先を探す手間も、メンテナーとのやり取りをする手間もかわりません。 (まあやったことないけど)
実際に報告した人のレポートにもありますが、「虎の威を借る」効果は多少期待できるでしょう。 CVEやIPAの名前だけ知っているというひとは多いでので、優先度を上げてくれるメンテナーも多いと思います。
脆弱性情報をIPAへ報告して修正されました #情報処理安全確保支援士 アカネちゃん、JVNに謝辞が載る:こうしす! こちら京姫鉄道 広報部システム課 @IT支線(17) - @IT 逆に言えば、脆弱性レポートの段階では、その程度の効果しかありません。
脆弱性の概要 lestrrat-go/jwxのJWEのデコード機能を利用する場合に、本脆弱性の影響を受ける可能性があります。
AES-CBCで暗号化されたデーターを復号するにはパディングを取り除く必要があります。 このとき不正なパディングを見つけた場合に “failed to generate plaintext from decrypted blocks: invalid padding” というエラーを返す実装になっていました。
背景 マイナンバーカードの導入により、今まで役所で行っていた証明書の発行手続きを、コンビニに行えるようになりました。 このコンビニ証明書交付サービスにおいて、2023年5月9日誤って他人の戸籍全部事項証明書が発行されてしまうバグが明らかになりました。
開発元である富士通Japan株式会社は、この原因について以下のように説明しています。
川崎市様における証明書誤交付ついて(お詫び) 本事象の原因は、2か所のコンビニで、2名の住民の方が同一タイミング(時間間隔1秒以内)で証明書の交付申請を行った際に、後続の処理が先行する処理を上書きしてしまうことによるものです。
「時間間隔1秒以内」という条件から、 Twitterを始めとしたSNSでは「タイムスタンプ(秒)をIDにしているのでは?」という憶測が広まりました。 (もしくはIDに類するもの)
ファイル名が秒単位の時刻なので、1秒間に複数申請があれば、後の申請の出力に上書きされてしまう、ということなのか。どうしてこれでうまくいくと思ったのか>富士通Japan https://t.co/FOvWWMdqar
— Haruhiko Okumura (@h_okumura) May 10, 2023 「そんなことやるわけないじゃん」とは思ったのですが、自分自身はともかく周りのひとは・・・?と考えたら心配になってきました。 そういうわけで、なぜタイムスタンプをIDとして扱ってはいけないのか、注意喚起することにしました。 もう話のネタとして旬は過ぎた感はあるけど、文章に残しておくことが大事なんだ。
なぜタイムスタンプをIDとして扱ってはいけないのか さて、「秒単位のタイムスタンプをIDに使う」という設計がなぜダメなのか考えていきましょう。
なお、今回の証明書誤交付の原因が「秒単位のタイムスタンプをIDに使ったため」と主張する意図はありません。 証明書発行システムの実装を例として、秒単位のタイムスタンプをIDに使った場合にどうなるか?という思考実験です。 実在のシステムとは関係ありません。
誕生日のパラドックス ダメな理由として挙げられるのは誕生日のパラドックスでしょう。
誕生日のパラドックス - Wikipedia たとえば、小中学校のクラスに同じ誕生日のペアがいたら、珍しいこともあるもんだ!と感じませんか? 実はそんなに珍しいことではないというのが誕生日のパラドックスです。 クラスに23人いれば、その中に「同じ誕生日である二人組」が50%以上の確率で存在します。
誕生日のパラドックスを証明書発行システムに当てはめて考えてみましょう。 ユーザーがいつ証明書発行を行うかわからないので、ユーザーは一年の中のランダムな時刻に証明書発行を行うと仮定します。 年間n人のユーザーが利用した場合にIDが重複する確率は、以下のプログラム(雑)で計算できます。
# python n = 60*60*24*365 p = 1.0 for i in range(n): p = p * (n - i) / n print(i, 1-p) 実行してみると年間6612人利用でIDが重複する確率が50%を超えます。 一年が3153.6万秒あることを考えると随分と少ないことがわかります。
... 6610 0.49986985152463326 6611 0.49997469552550755 6612 0.5000795334032722 6613 0.
CDNサービスで有名なAkamaiがユニクロとコラボしてTシャツを作りました。
本日、Akamaiは @UNIQLO_JP のチャリティTシャツプロジェクト「PEACE FOR ALL」に参画したことを発表4月21日(金)より グローバルで発売されます。このデザインには人々の安全、安心を守りたいというAkamaiの願いが込められています。https://t.co/HVxINmoEzd#AkamaiPeaceForAll #Uniqlo #アカマイ pic.twitter.com/dIS9YOQVZM
— アカマイ・テクノロジーズ (@akamai_jp) April 14, 2023 完全に二番煎じですが、Tシャツに描かれたコードを解読してみます。
Akamai x UNIQLOコラボTシャツに書かれたプログラムを解読してみる 解読してみる Tシャツに描かれたこのコード、PEACE FOR ALLに参画するために作られたのではなく、企業ブランドの一部として作られたもののようです。 Akamaiのウェブページをよく見てみると、背景にも同じコードが使われています。
コードの文脈をまったく意識せず切り貼りしたため、Tシャツのデザインでは失われてしまった部分があります(内容を理解できる人間にとってはちょっと残念)。 しかし、営業資料っぽいPDFに同じコードが利用されており、ここからなら十分に復元可能です。
クラウド投資のリターンを最大化 - Akamai EコーマスEマガジン 行ごとに分割して、同じ文字列が出現する箇所をつなぎ合わせると、以下のようなコードが浮かび上がります。
package main; import ( "fmt"; "html"; "log"; "net/http"; "strconv"; "strings"; "time" ); type ControlMessage struct { Target string; Count int64; }; func main() { controlChannel := make(chan ControlMessage);workerCompleteChan := make(chan bool); statusPollChannel := make(chan chan bool); workerActive := false;go admin(controlChannel, statusPollChannel); for { select { case respChan := <- statusPollChannel: respChan <- workerActive; case msg := <-controlChannel: workerActive = true; go doStuff(msg, workerCompleteChan); case status := <- workerCompleteChan: workerActive = status; }}}; func admin(cc chan ControlMessage, statusPollChannel chan chan bool) {http.