+ AES (crypto/aes) + GCM (crypto/cipher) Go 1.26以前のRSAハイブリッド暗号 1: // ====== 受信者(Recipient) ====== 2: // 3-1. RSA暗号化済みワンタイム共通鍵の長さを読み取る 3: var keyLen uint32 4: err := binary.Read(reader, binary.LittleEndian, &keyLen) 5: 6: // 3-2. RSA暗号化済みワンタイム共通鍵を取り出す 7: encryptedSessionKey := make([]byte, keyLen) 8: _, err := io.ReadFull(reader, encryptedSessionKey) 9: 10: // 3-3. ワンタイム共通鍵を復号 11: info := []byte("Encryption Key Label to Login") 12: sessionKey, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, privKey, encryptedSessionKey, info) 13: 14: // 3-4. Nonceを取り出す 15: gcmNonceSize := 12 16: nonce := make([]byte, gcmNonceSize) 17: _, err := io.ReadFull(reader, nonce) 18: 19: // 3-5. 残りのデータをAES暗号文として読み込む 20: cipherText, err := io.ReadAll(reader) 21: 22: // 3-6. AES-GCMで復号 23: aad := []byte("Additional Authenticated Data to Tom") 24: block, err := aes.NewCipher(sessionKey) 25: gcm, err := cipher.NewGCM(block) 26: plaintext, err := gcm.Open(nil, nonce, cipherText, aad) NG例: 共通鍵の復号とメッセージの復号時に異なるエラーで返却 こちらも攻撃者にRSA復号、AES復号どちらで失敗したか判別されてし まい、パディングオラクル攻撃のきっかけになる NG例: 暗号メッセージのサイズ検証不足 DoS攻撃により巨大な暗号メッセージを送りつけることでOOMを引き起 こしサービス停止が可能 NG例: 復号処理途中のエラーで Early Returnしてしまう エラーが返るまでのタイミングが異なると攻撃者にRSA復号のエラーか AES復号のエラーか判別する材料を与え、パディングオラクル攻撃の きっかけになる NG例: io.ReadFullではなくio.Readを利用してしまう io.Readは指定バイト数分を読み切る前に返ってしまう。