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

     1  // Copyright 2016 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 rsa_test
     6  
     7  import (
     8  	"github.com/shogo82148/std/crypto"
     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/crypto/rsa"
    13  	"github.com/shogo82148/std/crypto/sha256"
    14  	"github.com/shogo82148/std/encoding/hex"
    15  	"github.com/shogo82148/std/fmt"
    16  	"github.com/shogo82148/std/os"
    17  )
    18  
    19  // RSAは非常に限られた量のデータしか暗号化できません。したがって、合理的な量のデータを暗号化するためには、一般的にハイブリッド方式が使用されます。具体的には、RSAはAES-GCMのような対称プリミティブの鍵を暗号化するために使用されます。
    20  // 暗号化する前に、データは既知の構造に埋め込むことで「パディング」されます。これにはいくつかの理由がありますが、最も明らかな理由は、指数関数がモジュラスよりも大きい値になるようにするためです(そうしないと平方根で復号化できてしまいます)。
    21  // これらの設計では、PKCS #1 v1.5を使用する場合、受信したRSAメッセージが形式に適合しているか(つまり、復号化の結果が正しくパディングされたメッセージか)を漏らさないようにすることが重要です。そのためにDecryptPKCS1v15SessionKeyはこの状況に対応しており、復号化された対称鍵が適切な形式であれば、ランダムなキーを含むバッファ上で一定時間内に対称鍵をコピーします。したがって、RSAの結果が形式に適合していない場合は、実装が一定時間内にランダムなキーを使用します。
    22  func ExampleDecryptPKCS1v15SessionKey() {
    23  
    24  	// ハイブリッド方式では、少なくとも16バイトの対称鍵を使用する必要があります。ここでは、RSA復号が正しく形成されていない場合に使用されるランダムな鍵を読み取ります。
    25  	key := make([]byte, 32)
    26  	if _, err := rand.Read(key); err != nil {
    27  		panic("RNG failure")
    28  	}
    29  
    30  	rsaCiphertext, _ := hex.DecodeString("aabbccddeeff")
    31  
    32  	if err := rsa.DecryptPKCS1v15SessionKey(nil, rsaPrivateKey, rsaCiphertext, key); err != nil {
    33  
    34  		// 発生したエラーは「公開される」ものであり、秘密情報なしでも判断できます。(例えば、RSA公開鍵の長さが不可能な場合など)
    35  		fmt.Fprintf(os.Stderr, "Error from RSA decryption: %s\n", err)
    36  		return
    37  	}
    38  
    39  	// 与えられたキーを使用して、対称スキームを使ってより大きな暗号文を複合することができます。
    40  	block, err := aes.NewCipher(key)
    41  	if err != nil {
    42  		panic("aes.NewCipher failed: " + err.Error())
    43  	}
    44  
    45  	// キーがランダムであるため、固定されたNonceを使用することは許容されます。
    46  	// (キー、Nonce)のペアは依然として一意である必要があります。
    47  	var zeroNonce [12]byte
    48  	aead, err := cipher.NewGCM(block)
    49  	if err != nil {
    50  		panic("cipher.NewGCM failed: " + err.Error())
    51  	}
    52  	ciphertext, _ := hex.DecodeString("00112233445566")
    53  	plaintext, err := aead.Open(nil, zeroNonce[:], ciphertext, nil)
    54  	if err != nil {
    55  
    56  		// RSAの暗号文の形式が不正です。AES-GCMの鍵が正しくないため、復号化はここで失敗します。
    57  		fmt.Fprintf(os.Stderr, "Error decrypting: %s\n", err)
    58  		return
    59  	}
    60  
    61  	fmt.Printf("Plaintext: %s\n", plaintext)
    62  }
    63  
    64  func ExampleSignPKCS1v15() {
    65  	message := []byte("message to be signed")
    66  
    67  	// 直接署名できるのは小さなメッセージだけです。そのため、メッセージ自体ではなくそのハッシュを署名します。これにはハッシュ関数が衝突耐性がある必要があります。SHA-256は、執筆時点(2016年)では最も弱いハッシュ関数です。
    68  	hashed := sha256.Sum256(message)
    69  
    70  	signature, err := rsa.SignPKCS1v15(nil, rsaPrivateKey, crypto.SHA256, hashed[:])
    71  	if err != nil {
    72  		fmt.Fprintf(os.Stderr, "Error from signing: %s\n", err)
    73  		return
    74  	}
    75  
    76  	fmt.Printf("Signature: %x\n", signature)
    77  }
    78  
    79  func ExampleVerifyPKCS1v15() {
    80  	message := []byte("message to be signed")
    81  	signature, _ := hex.DecodeString("ad2766728615cc7a746cc553916380ca7bfa4f8983b990913bc69eb0556539a350ff0f8fe65ddfd3ebe91fe1c299c2fac135bc8c61e26be44ee259f2f80c1530")
    82  
    83  	// 直接署名できるのは小さなメッセージのみです。そのため、メッセージ自体ではなく、メッセージのハッシュが署名されます。これには、ハッシュ関数が衝突耐性を持つ必要があります。SHA-256は、書かれた時点(2016年)で使用すべき最も安全なハッシュ関数です。
    84  	hashed := sha256.Sum256(message)
    85  
    86  	err := rsa.VerifyPKCS1v15(&rsaPrivateKey.PublicKey, crypto.SHA256, hashed[:], signature)
    87  	if err != nil {
    88  		fmt.Fprintf(os.Stderr, "Error from verification: %s\n", err)
    89  		return
    90  	}
    91  
    92  	// シグネチャは公開鍵からのメッセージの有効な署名です。
    93  }
    94  
    95  func ExampleEncryptOAEP() {
    96  	secretMessage := []byte("send reinforcements, we're going to advance")
    97  	label := []byte("orders")
    98  
    99  	// crypto/rand.Readerは暗号化関数のランダム化において十分なエントロピー源です。
   100  	rng := rand.Reader
   101  
   102  	ciphertext, err := rsa.EncryptOAEP(sha256.New(), rng, &test2048Key.PublicKey, secretMessage, label)
   103  	if err != nil {
   104  		fmt.Fprintf(os.Stderr, "Error from encryption: %s\n", err)
   105  		return
   106  	}
   107  
   108  	// 暗号化はランダムな関数のため、暗号文は毎回異なるものとなります。
   109  	fmt.Printf("Ciphertext: %x\n", ciphertext)
   110  }
   111  
   112  func ExampleDecryptOAEP() {
   113  	ciphertext, _ := hex.DecodeString("4d1ee10e8f286390258c51a5e80802844c3e6358ad6690b7285218a7c7ed7fc3a4c7b950fbd04d4b0239cc060dcc7065ca6f84c1756deb71ca5685cadbb82be025e16449b905c568a19c088a1abfad54bf7ecc67a7df39943ec511091a34c0f2348d04e058fcff4d55644de3cd1d580791d4524b92f3e91695582e6e340a1c50b6c6d78e80b4e42c5b4d45e479b492de42bbd39cc642ebb80226bb5200020d501b24a37bcc2ec7f34e596b4fd6b063de4858dbf5a4e3dd18e262eda0ec2d19dbd8e890d672b63d368768360b20c0b6b8592a438fa275e5fa7f60bef0dd39673fd3989cc54d2cb80c08fcd19dacbc265ee1c6014616b0e04ea0328c2a04e73460")
   114  	label := []byte("orders")
   115  
   116  	plaintext, err := rsa.DecryptOAEP(sha256.New(), nil, test2048Key, ciphertext, label)
   117  	if err != nil {
   118  		fmt.Fprintf(os.Stderr, "Error from decryption: %s\n", err)
   119  		return
   120  	}
   121  
   122  	fmt.Printf("Plaintext: %s\n", plaintext)
   123  
   124  	// 暗号化は機密性のみを提供することを覚えておいてください。
   125  	// メッセージが正当性を想定した前に、暗号文には署名する必要があります。さらに、メッセージは順序が変更される可能性も考慮してください。
   126  }