...

パッケージ cipher

import "crypto/cipher"
概要
目次

概要 ▾

cipher パッケージは,低レベルブロック暗号実装にラップできる標準ブロック暗号モードを実装します。 https://csrc.nist.gov/groups/ST/toolkit/BCM/current_modes.html および NIST Special Publication 800-38A を参照してください。

type AEAD 1.2

AEAD は,関連付けられたデータと共に認証された暗号化を提供する暗号モードです。 方法論の説明については,下記を参照してください。

https://en.wikipedia.org/wiki/Authenticated_encryption
type AEAD interface {
    // NonceSize は, Seal と Open に渡す必要がある nonce のサイズを返します。
    NonceSize() int

    // Overheadは,平文とその暗号文の長さの最大差を返します。
    Overhead() int

    // Seal は平文を暗号化して認証し,追加データを認証して結果を dst に追加し,更新されたスライスを返します。
    // nonce は,与えられたキーに対して, NonceSize() バイト長で,常に一意でなければなりません。
    //
    // 平文の記憶域を暗号化された出力に再利用するには, dst として plaintext[:0] を使用します。
    // そうでなければ, dst の残りの容量は平文と重なってはいけません。
    Seal(dst, nonce, plaintext, additionalData []byte) []byte

    // Open は暗号文を復号化して認証し,追加データを認証し,成功した場合は,結果のプレーンテキストを dst に追加して,更新されたスライスを返します。
    // nonce は NonceSize() バイト長でなければならず,それと追加データの両方が Seal に渡された値と一致しなければなりません。
    //
    // 暗号化された出力を暗号化された出力に再利用するには, dst として ciphertext[:0] を使用します。
    // そうでなければ, dst の残りの容量は平文と重なってはいけません。
    //
    // 関数が失敗しても, dst の内容はその容量まで上書きされる可能性があります。
    Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error)
}

func NewGCM 1.2

func NewGCM(cipher Block) (AEAD, error)

NewGCM は,ガロアカウンタモードでラップされた,指定された 128 ビットのブロック暗号を標準のナンス長で返します。

一般に,この GCM の実装によって実行される GHASH 操作は一定時間ではありません。 例外は, AES をハードウェアでサポートしているシステムで,基盤となるブロックが aes.NewCipher によって作成された場合です。 詳細は crypto/aes パッケージのドキュメントを見てください。

例 (Decrypt)

コード:

// 安全な場所から秘密鍵をロードし,それを複数の Seal/Open 呼び出しで再利用してください。
// (当然です,このキーの例は実際のいずれの場所でも使わないでください。)
// パスフレーズを鍵に変換したい場合は, bcrypt や scrypt などの適切なパッケージを使用してください。
// デコードされたとき,キーは 16 バイト (AES-128) または 32 (AES-256) であるべきです。
key, _ := hex.DecodeString("6368616e676520746869732070617373776f726420746f206120736563726574")
ciphertext, _ := hex.DecodeString("c3aaa29f002ca75870806e44086700f62ce4d43e902b3888e23ceff797a7a471")
nonce, _ := hex.DecodeString("64a9433eae7ccceee2fc0eda")

block, err := aes.NewCipher(key)
if err != nil {
    panic(err.Error())
}

aesgcm, err := cipher.NewGCM(block)
if err != nil {
    panic(err.Error())
}

plaintext, err := aesgcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
    panic(err.Error())
}

fmt.Printf("%s\n", plaintext)

出力:

exampleplaintext

例 (Encrypt)

コード:

// 安全な場所から秘密鍵をロードし,それを複数の Seal/Open 呼び出しで再利用してください。
// (当然です,このキーの例は実際のいずれの場所でも使わないでください。)
// パスフレーズを鍵に変換したい場合は, bcrypt や scrypt などの適切なパッケージを使用してください。
// デコードされたとき,キーは 16 バイト (AES-128) または 32 (AES-256) であるべきです。
key, _ := hex.DecodeString("6368616e676520746869732070617373776f726420746f206120736563726574")
plaintext := []byte("exampleplaintext")

block, err := aes.NewCipher(key)
if err != nil {
    panic(err.Error())
}

// 繰り返しの危険があるため,特定のキーに 2^32 を超える乱数を使用しないでください。
nonce := make([]byte, 12)
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
    panic(err.Error())
}

aesgcm, err := cipher.NewGCM(block)
if err != nil {
    panic(err.Error())
}

ciphertext := aesgcm.Seal(nil, nonce, plaintext, nil)
fmt.Printf("%x\n", ciphertext)

func NewGCMWithNonceSize 1.5

func NewGCMWithNonceSize(cipher Block, size int) (AEAD, error)

NewGCMWithNonceSize は,指定された長さのナンスを受け入れるガロアカウンタモードでラップされた,指定された 128 ビットのブロック暗号を返します。

この機能は,標準外のナンス長を使用する既存の暗号システムとの互換性が必要な場合にのみ使用してください。 他のすべてのユーザーは,より早くより悪用に強いNewGCM を使うべきです。

func NewGCMWithTagSize 1.11

func NewGCMWithTagSize(cipher Block, tagSize int) (AEAD, error)

NewGCMWithTagSize は,指定された長さのタグを生成する,ガロアカウンタモードでラップされた指定された 128 ビットのブロック暗号を返します。

12 ~ 16 バイトのタグサイズが許可されています。

この機能は,標準以外のタグ長を使用する既存の暗号システムとの互換性が必要な場合にのみ使用してください。 他のすべてのユーザーはより悪用に強い NewGCM を使うべきです。

type Block

Blockは,与えられたキーを使ったブロック暗号の実装を表します。 個々のブロックを暗号化または復号化する機能を提供します。 モードの実装は,その機能をブロックのストリームに拡張します。

type Block interface {
    // BlockSize は暗号のブロックサイズを返します。
    BlockSize() int

    // Encrypt は, src の最初のブロックを dst に暗号化します。
    // Dst と src は完全に重なっているか,まったく重なっていない必要があります。
    Encrypt(dst, src []byte)

    // Decrypt は, src の最初のブロックを dst に復号化します。
    // Dst と src は完全に重なっているか,まったく重なっていない必要があります。
    Decrypt(dst, src []byte)
}

type BlockMode

BlockMode は,ブロックベースモード (CBC , ECB など) で実行されているブロック暗号を表します。

type BlockMode interface {
    // BlockSize はモードのブロックサイズを返します。
    BlockSize() int

    // CryptBlocks はいくつかのブロックを暗号化または復号化します。
    // src の長さはブロックサイズの倍数でなければなりません。
    // Dst と src は完全に重なっているか,まったく重なっていない必要があります。
    //
    // len(dst) < len(src) の場合, CryptBlocks はパニックを起こすはずです。
    // src よりも大きい dst を渡すことは許容できます。
    // その場合, CryptBlocks は dst[:len(src)] を更新するだけで,残りの dst には触れません。
    //
    // CryptBlocks への複数の呼び出しは, src バッファの連結が 1 回の実行で渡されたように動作します。
    // つまり, BlockMode は状態を維持し,各 CryptBlocks 呼び出しでリセットされません。
    CryptBlocks(dst, src []byte)
}

func NewCBCDecrypter

func NewCBCDecrypter(b Block, iv []byte) BlockMode

NewCBCDecrypter は与えられた Block を使って暗号ブロック連鎖モードで復号化する BlockMode を返します。 iv の長さはブロックのブロックサイズと同じでなければならず,データの暗号化に使用された iv と一致しなければなりません。

コード:

// 安全な場所から秘密鍵をロードし,それを複数の NewCipher 呼び出しで再利用してください。
// (当然です,このキーの例は実際のいずれの場所でも使わないでください。)
// パスフレーズを鍵に変換したい場合は, bcrypt や scrypt などの適切なパッケージを使用してください。
key, _ := hex.DecodeString("6368616e676520746869732070617373")
ciphertext, _ := hex.DecodeString("73c86d43a9d700a253a96c85b0f6b03ac9792e0e757f869cca306bd3cba1c62b")

block, err := aes.NewCipher(key)
if err != nil {
    panic(err)
}

// IV は一意である必要がありますが,安全である必要はありません。
// そのため,暗号文の冒頭に含めるのが一般的です。
if len(ciphertext) < aes.BlockSize {
    panic("ciphertext too short")
}
iv := ciphertext[:aes.BlockSize]
ciphertext = ciphertext[aes.BlockSize:]

// CBC モードは常にブロック全体で機能します。
if len(ciphertext)%aes.BlockSize != 0 {
    panic("ciphertext is not a multiple of the block size")
}

mode := cipher.NewCBCDecrypter(block, iv)

// 2 つの引数が同じ場合, CryptBlocks はその場で機能します。
mode.CryptBlocks(ciphertext, ciphertext)

// 元の平文の長さがブロックサイズの倍数でない場合は,暗号化時にパディングを追加する必要があります。
// これはこの時点で削除されます。
// 例については, https://tools.ietf.org/html/rfc5246#section-6.2.3.2 を参照してください。
// ただし,パディングオラクルを作成しないようにするには,暗号文を復号化する前に (すなわちcrypto/hmac を使用して) 認証する必要があることに注意することが重要です。

fmt.Printf("%s\n", ciphertext)

出力:

exampleplaintext

func NewCBCEncrypter

func NewCBCEncrypter(b Block, iv []byte) BlockMode

NewCBCEncrypter は,与えられた Block を使って暗号ブロック連鎖モードで暗号化する BlockMode を返します。 iv の長さはブロックのブロックサイズと同じでなければなりません。

コード:

// 安全な場所から秘密鍵をロードし,それを複数の NewCipher 呼び出しで再利用してください。
// (当然です,このキーの例は実際のいずれの場所でも使わないでください。)
// パスフレーズを鍵に変換したい場合は, bcrypt や scrypt などの適切なパッケージを使用してください。
key, _ := hex.DecodeString("6368616e676520746869732070617373")
plaintext := []byte("exampleplaintext")

// CBC モードはブロックに対して機能するため,プレーンテキストを次のブロック全体にパディングする必要があるかもしれません。
// このようなパディングの例については, https://tools.ietf.org/html/rfc5246#section-6.2.3.2 を参照してください。
// ここでは平文がすでに正しい長さであると仮定します。
if len(plaintext)%aes.BlockSize != 0 {
    panic("plaintext is not a multiple of the block size")
}

block, err := aes.NewCipher(key)
if err != nil {
    panic(err)
}

// IV は一意である必要がありますが,安全である必要はありません。
// そのため,暗号文の冒頭に含めるのが一般的です。
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
    panic(err)
}

mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)

// 安全であるためには,暗号文は認証されなければならない (すなわち, crypto/hmac を使用する) 必要があることを覚えておくことが重要です。

fmt.Printf("%x\n", ciphertext)

type Stream

Stream はストリーム暗号を表します。

type Stream interface {
    // XORKeyStream は指定されたスライス内の各バイトと,暗号のキーストリームからのバイトとの排他的論理和をとります。
    // Dst と src は完全に重なっているか,まったく重なっていない必要があります。
    //
    // len(dst) < len(src) の場合, XORKeyStream はパニックを起こすはずです。
    // src よりも大きい dst を渡すことは許容できます。
    // その場合, XORKeyStream は dst[:len(src)] を更新するだけで,残りの dst には触れません。
    //
    // XORKeyStream への複数の呼び出しは, src バッファの連結が 1 回の実行で渡された場合と同じように動作します。
    // つまり, Stream は状態を維持し,各 XORKeyStream 呼び出しでリセットされません。
    XORKeyStream(dst, src []byte)
}

func NewCFBDecrypter

func NewCFBDecrypter(block Block, iv []byte) Stream

NewCFBDecrypter は,与えられた Block を使って暗号フィードバックモードで復号化する Stream を返します。 iv はブロックのブロックサイズと同じ長さでなければなりません。

コード:

// 安全な場所から秘密鍵をロードし,それを複数の NewCipher 呼び出しで再利用してください。
// (当然です,このキーの例は実際のいずれの場所でも使わないでください。)
// パスフレーズを鍵に変換したい場合は, bcrypt や scrypt などの適切なパッケージを使用してください。
key, _ := hex.DecodeString("6368616e676520746869732070617373")
ciphertext, _ := hex.DecodeString("7dd015f06bec7f1b8f6559dad89f4131da62261786845100056b353194ad")

block, err := aes.NewCipher(key)
if err != nil {
    panic(err)
}

// IV は一意である必要がありますが,安全である必要はありません。
// そのため,暗号文の冒頭に含めるのが一般的です。
if len(ciphertext) < aes.BlockSize {
    panic("ciphertext too short")
}
iv := ciphertext[:aes.BlockSize]
ciphertext = ciphertext[aes.BlockSize:]

stream := cipher.NewCFBDecrypter(block, iv)

// 2 つの引数が同じ場合, XORKeyStream はその場で機能します。
stream.XORKeyStream(ciphertext, ciphertext)
fmt.Printf("%s", ciphertext)

出力:

some plaintext

func NewCFBEncrypter

func NewCFBEncrypter(block Block, iv []byte) Stream

NewCFBEncrypter は,与えられた Block を使って暗号フィードバックモードで暗号化する Stream を返します。 iv はブロックのブロックサイズと同じ長さでなければなりません。

コード:

// 安全な場所から秘密鍵をロードし,それを複数の NewCipher 呼び出しで再利用してください。
// (当然です,このキーの例は実際のいずれの場所でも使わないでください。)
// パスフレーズを鍵に変換したい場合は, bcrypt や scrypt などの適切なパッケージを使用してください。
key, _ := hex.DecodeString("6368616e676520746869732070617373")
plaintext := []byte("some plaintext")

block, err := aes.NewCipher(key)
if err != nil {
    panic(err)
}

// IV は一意である必要がありますが,安全である必要はありません。
// そのため,暗号文の冒頭に含めるのが一般的です。
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
    panic(err)
}

stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)

// 安全であるためには,暗号文は認証されなければならない (すなわち, crypto/hmac を使用する) 必要があることを覚えておくことが重要です。
fmt.Printf("%x\n", ciphertext)

func NewCTR

func NewCTR(block Block, iv []byte) Stream

NewCTR は,指定されたブロックをカウンターモードで使用して暗号化 / 復号化する Stream を返します。 iv の長さはブロックのブロックサイズと同じでなければなりません。

コード:

// 安全な場所から秘密鍵をロードし,それを複数の NewCipher 呼び出しで再利用してください。
// (当然です,このキーの例は実際のいずれの場所でも使わないでください。)
// パスフレーズを鍵に変換したい場合は, bcrypt や scrypt などの適切なパッケージを使用してください。
key, _ := hex.DecodeString("6368616e676520746869732070617373")
plaintext := []byte("some plaintext")

block, err := aes.NewCipher(key)
if err != nil {
    panic(err)
}

// IV は一意である必要がありますが,安全である必要はありません。
// そのため,暗号文の冒頭に含めるのが一般的です。
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
    panic(err)
}

stream := cipher.NewCTR(block, iv)
stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)

// 安全であるためには,暗号文は認証されなければならない (すなわち, crypto/hmac を使用する) 必要があることを覚えておくことが重要です。

// CTR モードは暗号化と復号化の両方で同じであるため, NewCTR を使用してその暗号文を復号化することもできます。

plaintext2 := make([]byte, len(plaintext))
stream = cipher.NewCTR(block, iv)
stream.XORKeyStream(plaintext2, ciphertext[aes.BlockSize:])

fmt.Printf("%s\n", plaintext2)

出力:

some plaintext

func NewOFB

func NewOFB(b Block, iv []byte) Stream

NewOFB は,出力フィードバックモードでブロック暗号 b を使用して暗号化または復号化する Stream を返します。 初期化ベクトル iv の長さは, b のブロックサイズと等しくなければなりません。

コード:

// 安全な場所から秘密鍵をロードし,それを複数の NewCipher 呼び出しで再利用してください。
// (当然です,このキーの例は実際のいずれの場所でも使わないでください。)
// パスフレーズを鍵に変換したい場合は, bcrypt や scrypt などの適切なパッケージを使用してください。
key, _ := hex.DecodeString("6368616e676520746869732070617373")
plaintext := []byte("some plaintext")

block, err := aes.NewCipher(key)
if err != nil {
    panic(err)
}

// IV は一意である必要がありますが,安全である必要はありません。
// そのため,暗号文の冒頭に含めるのが一般的です。
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
    panic(err)
}

stream := cipher.NewOFB(block, iv)
stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)

// 安全であるためには,暗号文は認証されなければならない (すなわち, crypto/hmac を使用する) 必要があることを覚えておくことが重要です。

// OFB モードは暗号化と復号化の両方で同じであるため, NewOFB を使用してその暗号文を復号化することもできます。

plaintext2 := make([]byte, len(plaintext))
stream = cipher.NewOFB(block, iv)
stream.XORKeyStream(plaintext2, ciphertext[aes.BlockSize:])

fmt.Printf("%s\n", plaintext2)

出力:

some plaintext

type StreamReader

StreamReader は Stream を io.Reader にラップします。 通過するデータの各スライスを処理するために XORKeyStream を呼び出します。

type StreamReader struct {
    S Stream
    R io.Reader
}

コード:

// 安全な場所から秘密鍵をロードし,それを複数の NewCipher 呼び出しで再利用してください。
// (当然です,このキーの例は実際のいずれの場所でも使わないでください。)
// パスフレーズを鍵に変換したい場合は, bcrypt や scrypt などの適切なパッケージを使用してください。
key, _ := hex.DecodeString("6368616e676520746869732070617373")

encrypted, _ := hex.DecodeString("cf0495cc6f75dafc23948538e79904a9")
bReader := bytes.NewReader(encrypted)

block, err := aes.NewCipher(key)
if err != nil {
    panic(err)
}

// 鍵が各暗号文に固有の場合は,ゼロの IV を使用してもかまいません。
var iv [aes.BlockSize]byte
stream := cipher.NewOFB(block, iv[:])

reader := &cipher.StreamReader{S: stream, R: bReader}
// 入力を出力ストリームにコピーして,復号化します。
if _, err := io.Copy(os.Stdout, reader); err != nil {
    panic(err)
}

// この例は,暗号化されたデータの認証を省略するという点で単純化されていることに注意してください。
// 実際にこの方法で StreamReader を使用すると,攻撃者が出力内の任意のビットを反転させる可能性があります。

出力:

some secret text

func (StreamReader) Read

func (r StreamReader) Read(dst []byte) (n int, err error)

type StreamWriter

StreamWriter は Stream を io.Writer にラップします。 通過するデータの各スライスを処理するために XORKeyStream を呼び出します。 いずれかの Write 呼び出しが不足と返した場合, StreamWriter は同期がとれていないため,破棄する必要があります。 StreamWriter には内部バッファリングはありません。 書き込みデータをフラッシュするために close を呼び出す必要はありません。

type StreamWriter struct {
    S   Stream
    W   io.Writer
    Err error // 未使用
}

コード:

// 安全な場所から秘密鍵をロードし,それを複数の NewCipher 呼び出しで再利用してください。
// (当然です,このキーの例は実際のいずれの場所でも使わないでください。)
// パスフレーズを鍵に変換したい場合は, bcrypt や scrypt などの適切なパッケージを使用してください。
key, _ := hex.DecodeString("6368616e676520746869732070617373")

bReader := bytes.NewReader([]byte("some secret text"))

block, err := aes.NewCipher(key)
if err != nil {
    panic(err)
}

// 鍵が各暗号文に固有の場合は,ゼロの IV を使用してもかまいません。
var iv [aes.BlockSize]byte
stream := cipher.NewOFB(block, iv[:])

var out bytes.Buffer

writer := &cipher.StreamWriter{S: stream, W: &out}
// 入力を出力バッファにコピーし,暗号化を進めます。
if _, err := io.Copy(writer, bReader); err != nil {
    panic(err)
}

// この例は,暗号化されたデータの認証を省略するという点で単純化されています。
// 実際にこの方法で StreamReader を使用すると,攻撃者が復号結果の任意のビットを反転させる可能性があります。

fmt.Printf("%x\n", out.Bytes())

出力:

cf0495cc6f75dafc23948538e79904a9

func (StreamWriter) Close

func (w StreamWriter) Close() error

Writer が io.Closer でもある場合, Close は内部の Writer を閉じて,その Close 戻り値を返します。 そうでなければ nil を返します。

func (StreamWriter) Write

func (w StreamWriter) Write(src []byte) (n int, err error)