github.com/shogo82148/std@v1.22.1-0.20240327122250-4e474527810c/crypto/cipher/example_test.go (about)

     1  // Copyright 2012 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package cipher_test
     6  
     7  import (
     8  	"github.com/shogo82148/std/bytes"
     9  	"github.com/shogo82148/std/crypto/aes"
    10  	"github.com/shogo82148/std/crypto/cipher"
    11  	"github.com/shogo82148/std/crypto/rand"
    12  	"github.com/shogo82148/std/encoding/hex"
    13  	"github.com/shogo82148/std/fmt"
    14  	"github.com/shogo82148/std/io"
    15  	"github.com/shogo82148/std/os"
    16  )
    17  
    18  func ExampleNewGCM_encrypt() {
    19  
    20  	// 安全な場所から秘密鍵を読み込み、複数のSeal/Open呼び出しで再利用します。
    21  	//(もちろん、実際の用途にはこの例の鍵を使用しないでください。)
    22  	// パスフレーズを鍵に変換したい場合は、bcryptやscryptのような適切な
    23  	// パッケージを使用してください。
    24  	// デコードされた鍵は16バイト(AES-128)または32バイト(AES-256)である必要があります。
    25  	key, _ := hex.DecodeString("6368616e676520746869732070617373776f726420746f206120736563726574")
    26  	plaintext := []byte("exampleplaintext")
    27  
    28  	block, err := aes.NewCipher(key)
    29  	if err != nil {
    30  		panic(err.Error())
    31  	}
    32  
    33  	// 同じキーで2^32以上のランダムなノンスを使用しないでください。繰り返しのリスクがあるためです。
    34  	nonce := make([]byte, 12)
    35  	if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
    36  		panic(err.Error())
    37  	}
    38  
    39  	aesgcm, err := cipher.NewGCM(block)
    40  	if err != nil {
    41  		panic(err.Error())
    42  	}
    43  
    44  	ciphertext := aesgcm.Seal(nil, nonce, plaintext, nil)
    45  	fmt.Printf("%x\n", ciphertext)
    46  }
    47  
    48  func ExampleNewGCM_decrypt() {
    49  
    50  	// 安全な場所から秘密のキーを読み込み、複数のSeal/Open呼び出し間で再利用してください。
    51  	// (もちろん、実際の用途にはこの例のキーを使用しないでください。)
    52  	// パスフレーズをキーに変換したい場合は、bcryptやscryptなどの適切なパッケージを使用してください。
    53  	// キーをデコードすると、16バイト(AES-128)または32バイト(AES-256)である必要があります。
    54  	key, _ := hex.DecodeString("6368616e676520746869732070617373776f726420746f206120736563726574")
    55  	ciphertext, _ := hex.DecodeString("c3aaa29f002ca75870806e44086700f62ce4d43e902b3888e23ceff797a7a471")
    56  	nonce, _ := hex.DecodeString("64a9433eae7ccceee2fc0eda")
    57  
    58  	block, err := aes.NewCipher(key)
    59  	if err != nil {
    60  		panic(err.Error())
    61  	}
    62  
    63  	aesgcm, err := cipher.NewGCM(block)
    64  	if err != nil {
    65  		panic(err.Error())
    66  	}
    67  
    68  	plaintext, err := aesgcm.Open(nil, nonce, ciphertext, nil)
    69  	if err != nil {
    70  		panic(err.Error())
    71  	}
    72  
    73  	fmt.Printf("%s\n", plaintext)
    74  	// Output: exampleplaintext
    75  }
    76  
    77  func ExampleNewCBCDecrypter() {
    78  
    79  	// 安全な場所から秘密鍵を読み込んで、複数の NewCipher 呼び出し間で再利用してください。
    80  	// (もちろん、実際の用途にはこの例の鍵を使用しないでください。)
    81  	// パスフレーズを鍵に変換したい場合は、bcrypt や scrypt のような適切なパッケージを使用してください。
    82  	key, _ := hex.DecodeString("6368616e676520746869732070617373")
    83  	ciphertext, _ := hex.DecodeString("73c86d43a9d700a253a96c85b0f6b03ac9792e0e757f869cca306bd3cba1c62b")
    84  
    85  	block, err := aes.NewCipher(key)
    86  	if err != nil {
    87  		panic(err)
    88  	}
    89  
    90  	// IVは一意である必要がありますが、セキュリティは必要ありません。
    91  	// そのため、しばしば暗号文の先頭に含まれます。
    92  	if len(ciphertext) < aes.BlockSize {
    93  		panic("ciphertext too short")
    94  	}
    95  	iv := ciphertext[:aes.BlockSize]
    96  	ciphertext = ciphertext[aes.BlockSize:]
    97  
    98  	// CBCモードは常に完全なブロックで動作します。
    99  	if len(ciphertext)%aes.BlockSize != 0 {
   100  		panic("ciphertext is not a multiple of the block size")
   101  	}
   102  
   103  	mode := cipher.NewCBCDecrypter(block, iv)
   104  
   105  	// CryptBlocks は、引数が同じであればその場で処理されます。
   106  	mode.CryptBlocks(ciphertext, ciphertext)
   107  
   108  	// もし元の平文の長さがブロックの倍数でない場合、暗号化する際に追加する必要があるパディングがこの時点で削除されます。例としては、https://tools.ietf.org/html/rfc5246#section-6.2.3.2 を参照してください。ただし、パディングオラクルを作成しないために、暗号文を複合化する前に必ず認証すること(つまり、crypto/hmacを使用すること)が非常に重要です。
   109  
   110  	fmt.Printf("%s\n", ciphertext)
   111  	// Output: exampleplaintext
   112  }
   113  
   114  func ExampleNewCBCEncrypter() {
   115  
   116  	// 安全な場所から秘密の鍵をロードし、複数の NewCipher 呼び出しで再利用します。
   117  	// (もちろん、実際の目的にはこの例の鍵を使用しないでください。)
   118  	// もしパスフレーズを鍵に変換したい場合は、bcrypt や scrypt のような適切なパッケージを使用してください。
   119  	key, _ := hex.DecodeString("6368616e676520746869732070617373")
   120  	plaintext := []byte("exampleplaintext")
   121  
   122  	// CBCモードでは、平文はブロック単位で処理されるため、次の完全なブロックまでパディングする必要がある場合があります。このようなパディングの例については、次を参照してください:https://tools.ietf.org/html/rfc5246#section-6.2.3.2。ここでは、平文が既に正しい長さであると仮定します。
   123  	if len(plaintext)%aes.BlockSize != 0 {
   124  		panic("plaintext is not a multiple of the block size")
   125  	}
   126  
   127  	block, err := aes.NewCipher(key)
   128  	if err != nil {
   129  		panic(err)
   130  	}
   131  
   132  	// IVはユニークである必要がありますが、セキュリティは求められません。
   133  	// そのため、一般的には暗号文の先頭に含めることがあります。
   134  	ciphertext := make([]byte, aes.BlockSize+len(plaintext))
   135  	iv := ciphertext[:aes.BlockSize]
   136  	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
   137  		panic(err)
   138  	}
   139  
   140  	mode := cipher.NewCBCEncrypter(block, iv)
   141  	mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)
   142  
   143  	// 暗号文は、安全にするために暗号化されるだけでなく、
   144  	// (つまり、crypto/hmacを使用することによって)認証されている必要があることを忘れないことが重要です。
   145  
   146  	fmt.Printf("%x\n", ciphertext)
   147  }
   148  
   149  func ExampleNewCFBDecrypter() {
   150  
   151  	// 安全な場所から秘密キーを読み込み、複数のNewCipher呼び出しで再利用してください。
   152  	// (もちろん、実際にはこの例のキーを使用しないでください。)パスフレーズをキーに変換したい場合は、bcryptやscryptなど適切なパッケージを使用してください。
   153  	key, _ := hex.DecodeString("6368616e676520746869732070617373")
   154  	ciphertext, _ := hex.DecodeString("7dd015f06bec7f1b8f6559dad89f4131da62261786845100056b353194ad")
   155  
   156  	block, err := aes.NewCipher(key)
   157  	if err != nil {
   158  		panic(err)
   159  	}
   160  
   161  	// IVは一意である必要がありますが、安全性は問われません。したがって、通常は暗号文の先頭に含まれます。
   162  	if len(ciphertext) < aes.BlockSize {
   163  		panic("ciphertext too short")
   164  	}
   165  	iv := ciphertext[:aes.BlockSize]
   166  	ciphertext = ciphertext[aes.BlockSize:]
   167  
   168  	stream := cipher.NewCFBDecrypter(block, iv)
   169  
   170  	// もし2つの引数が同じ場合、XORKeyStreamはインプレースで動作することができます。
   171  	stream.XORKeyStream(ciphertext, ciphertext)
   172  	fmt.Printf("%s", ciphertext)
   173  	// Output: some plaintext
   174  }
   175  
   176  func ExampleNewCFBEncrypter() {
   177  
   178  	// 安全な場所から秘密鍵を読み込み、複数の NewCipher 呼び出しで再利用してください。 (明らかに、実際の何かのためにこの例の鍵を使用しないでください)。 パスフレーズを鍵に変換したい場合は、bcrypt や scrypt のような適切なパッケージを使用してください。
   179  	key, _ := hex.DecodeString("6368616e676520746869732070617373")
   180  	plaintext := []byte("some plaintext")
   181  
   182  	block, err := aes.NewCipher(key)
   183  	if err != nil {
   184  		panic(err)
   185  	}
   186  
   187  	// IVは一意である必要がありますが、安全である必要はありません。したがって、一般的には、暗号文の先頭にIVを含めることがあります。
   188  	ciphertext := make([]byte, aes.BlockSize+len(plaintext))
   189  	iv := ciphertext[:aes.BlockSize]
   190  	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
   191  		panic(err)
   192  	}
   193  
   194  	stream := cipher.NewCFBEncrypter(block, iv)
   195  	stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
   196  
   197  	// 暗号文は、安全性を確保するために、暗号化だけでなく、認証(crypto/hmac の使用によって)も行われる必要があることを覚えておくことが重要です。
   198  	fmt.Printf("%x\n", ciphertext)
   199  }
   200  
   201  func ExampleNewCTR() {
   202  
   203  	// 安全な場所から秘密キーを読み込み、複数のNewCipher呼び出しで再利用します。
   204  	// (もちろん、実際の用途にはこの例のキーを使用しないでください。)
   205  	// パスフレーズをキーに変換したい場合は、bcryptやscryptのような適切なパッケージを使用してください。
   206  	key, _ := hex.DecodeString("6368616e676520746869732070617373")
   207  	plaintext := []byte("some plaintext")
   208  
   209  	block, err := aes.NewCipher(key)
   210  	if err != nil {
   211  		panic(err)
   212  	}
   213  
   214  	// IVは一意である必要がありますが、セキュリティは必要ありません。そのため、一般的には暗号文の先頭に含まれます。
   215  	ciphertext := make([]byte, aes.BlockSize+len(plaintext))
   216  	iv := ciphertext[:aes.BlockSize]
   217  	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
   218  		panic(err)
   219  	}
   220  
   221  	stream := cipher.NewCTR(block, iv)
   222  	stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
   223  
   224  	// 暗号文は安全にするために、暗号化するだけでなく、認証(つまりcrypto/hmacを使用すること)することも重要であることを忘れないようにする必要があります。
   225  
   226  	// CTR モードは暗号化と復号化の両方に同じですので、NewCTR を使ってその暗号文を復号化することもできます。
   227  
   228  	plaintext2 := make([]byte, len(plaintext))
   229  	stream = cipher.NewCTR(block, iv)
   230  	stream.XORKeyStream(plaintext2, ciphertext[aes.BlockSize:])
   231  
   232  	fmt.Printf("%s\n", plaintext2)
   233  	// Output: some plaintext
   234  }
   235  
   236  func ExampleNewOFB() {
   237  
   238  	// 安全な場所から秘密鍵を読み込み、複数の NewCipher 呼び出しで再利用します。
   239  	//(もちろん、実際の用途にはこの例の鍵を使用しないでください。)もしパスフレーズを鍵に変換したい場合は、bcrypt や scrypt のような適切なパッケージを使用してください。
   240  	key, _ := hex.DecodeString("6368616e676520746869732070617373")
   241  	plaintext := []byte("some plaintext")
   242  
   243  	block, err := aes.NewCipher(key)
   244  	if err != nil {
   245  		panic(err)
   246  	}
   247  
   248  	// IVは一意である必要がありますが、セキュリティは必要ありません。そのため、一般的には
   249  	// 暗号文の先頭に含まれています。
   250  	ciphertext := make([]byte, aes.BlockSize+len(plaintext))
   251  	iv := ciphertext[:aes.BlockSize]
   252  	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
   253  		panic(err)
   254  	}
   255  
   256  	stream := cipher.NewOFB(block, iv)
   257  	stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
   258  
   259  	// 暗号文だけでなく、(crypto/hmacを使用して)認証も行われる必要があることを覚えておくことは重要です。これによってセキュリティが確保されます。
   260  
   261  	// OFBモードは暗号化と復号化の両方において同じですので、NewOFBを使ってその暗号文を復号化することも可能です。
   262  
   263  	plaintext2 := make([]byte, len(plaintext))
   264  	stream = cipher.NewOFB(block, iv)
   265  	stream.XORKeyStream(plaintext2, ciphertext[aes.BlockSize:])
   266  
   267  	fmt.Printf("%s\n", plaintext2)
   268  	// Output: some plaintext
   269  }
   270  
   271  func ExampleStreamReader() {
   272  
   273  	// 安全な場所から秘密の鍵をロードし、複数の NewCipher 呼び出しで再利用してください。
   274  	// (もちろん、これは実際には使用しないでください。)パスフレーズを鍵に変換したい場合は、bcrypt や scrypt のような適切なパッケージを使用してください。
   275  	key, _ := hex.DecodeString("6368616e676520746869732070617373")
   276  
   277  	encrypted, _ := hex.DecodeString("cf0495cc6f75dafc23948538e79904a9")
   278  	bReader := bytes.NewReader(encrypted)
   279  
   280  	block, err := aes.NewCipher(key)
   281  	if err != nil {
   282  		panic(err)
   283  	}
   284  
   285  	// もしキーがそれぞれの暗号文ごとにユニークである場合、ゼロの初期化ベクトル(IV)を使用しても問題ありません。
   286  	var iv [aes.BlockSize]byte
   287  	stream := cipher.NewOFB(block, iv[:])
   288  
   289  	reader := &cipher.StreamReader{S: stream, R: bReader}
   290  	// 入力を出力ストリームにコピーし、逐次復号化する。
   291  	if _, err := io.Copy(os.Stdout, reader); err != nil {
   292  		panic(err)
   293  	}
   294  
   295  	// この例では、暗号化されたデータの認証を省略しているため、単純化されています。実際にこのようにStreamReaderを使用する場合、攻撃者は出力の任意のビットを反転させることができます。
   296  
   297  	// Output: some secret text
   298  }
   299  
   300  func ExampleStreamWriter() {
   301  
   302  	// 安全な場所から秘密キーを読み込み、複数の NewCipher 呼び出しで再利用します。
   303  	// (もちろん、実際の用途でこの例のキーを使用しないでください。)
   304  	// もしパスフレーズをキーに変換したい場合は、bcrypt や scrypt のような
   305  	// 適切なパッケージを使用してください。
   306  	key, _ := hex.DecodeString("6368616e676520746869732070617373")
   307  
   308  	bReader := bytes.NewReader([]byte("some secret text"))
   309  
   310  	block, err := aes.NewCipher(key)
   311  	if err != nil {
   312  		panic(err)
   313  	}
   314  
   315  	// キーが各暗号文ごとにユニークな場合、ゼロのIVを使用することは問題ありません。
   316  	var iv [aes.BlockSize]byte
   317  	stream := cipher.NewOFB(block, iv[:])
   318  
   319  	var out bytes.Buffer
   320  
   321  	writer := &cipher.StreamWriter{S: stream, W: &out}
   322  	// 入力を出力バッファにコピーし、進行中に暗号化します。
   323  	if _, err := io.Copy(writer, bReader); err != nil {
   324  		panic(err)
   325  	}
   326  
   327  	// この例は暗号化されたデータの認証を省略して簡略化しています。実際にStreamReaderをこのように使用する場合、攻撃者が復号化された結果内の任意のビットを反転させる可能性があります。
   328  
   329  	fmt.Printf("%x\n", out.Bytes())
   330  	// Output: cf0495cc6f75dafc23948538e79904a9
   331  }