Source file src/crypto/rsa/example_test.go

     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  	"crypto"
     9  	"crypto/aes"
    10  	"crypto/cipher"
    11  	"crypto/rand"
    12  	"crypto/rsa"
    13  	"crypto/sha256"
    14  	"encoding/hex"
    15  	"fmt"
    16  	"os"
    17  )
    18  
    19  // RSA is able to encrypt only a very limited amount of data. In order
    20  // to encrypt reasonable amounts of data a hybrid scheme is commonly
    21  // used: RSA is used to encrypt a key for a symmetric primitive like
    22  // AES-GCM.
    23  //
    24  // Before encrypting, data is “padded” by embedding it in a known
    25  // structure. This is done for a number of reasons, but the most
    26  // obvious is to ensure that the value is large enough that the
    27  // exponentiation is larger than the modulus. (Otherwise it could be
    28  // decrypted with a square-root.)
    29  //
    30  // In these designs, when using PKCS #1 v1.5, it's vitally important to
    31  // avoid disclosing whether the received RSA message was well-formed
    32  // (that is, whether the result of decrypting is a correctly padded
    33  // message) because this leaks secret information.
    34  // DecryptPKCS1v15SessionKey is designed for this situation and copies
    35  // the decrypted, symmetric key (if well-formed) in constant-time over
    36  // a buffer that contains a random key. Thus, if the RSA result isn't
    37  // well-formed, the implementation uses a random key in constant time.
    38  func ExampleDecryptPKCS1v15SessionKey() {
    39  	// The hybrid scheme should use at least a 16-byte symmetric key. Here
    40  	// we read the random key that will be used if the RSA decryption isn't
    41  	// well-formed.
    42  	key := make([]byte, 32)
    43  	if _, err := rand.Read(key); err != nil {
    44  		panic("RNG failure")
    45  	}
    46  
    47  	rsaCiphertext, _ := hex.DecodeString("aabbccddeeff")
    48  
    49  	if err := rsa.DecryptPKCS1v15SessionKey(nil, rsaPrivateKey, rsaCiphertext, key); err != nil {
    50  		// Any errors that result will be “public” – meaning that they
    51  		// can be determined without any secret information. (For
    52  		// instance, if the length of key is impossible given the RSA
    53  		// public key.)
    54  		fmt.Fprintf(os.Stderr, "Error from RSA decryption: %s\n", err)
    55  		return
    56  	}
    57  
    58  	// Given the resulting key, a symmetric scheme can be used to decrypt a
    59  	// larger ciphertext.
    60  	block, err := aes.NewCipher(key)
    61  	if err != nil {
    62  		panic("aes.NewCipher failed: " + err.Error())
    63  	}
    64  
    65  	// Since the key is random, using a fixed nonce is acceptable as the
    66  	// (key, nonce) pair will still be unique, as required.
    67  	var zeroNonce [12]byte
    68  	aead, err := cipher.NewGCM(block)
    69  	if err != nil {
    70  		panic("cipher.NewGCM failed: " + err.Error())
    71  	}
    72  	ciphertext, _ := hex.DecodeString("00112233445566")
    73  	plaintext, err := aead.Open(nil, zeroNonce[:], ciphertext, nil)
    74  	if err != nil {
    75  		// The RSA ciphertext was badly formed; the decryption will
    76  		// fail here because the AES-GCM key will be incorrect.
    77  		fmt.Fprintf(os.Stderr, "Error decrypting: %s\n", err)
    78  		return
    79  	}
    80  
    81  	fmt.Printf("Plaintext: %s\n", plaintext)
    82  }
    83  
    84  func ExampleSignPKCS1v15() {
    85  	message := []byte("message to be signed")
    86  
    87  	// Only small messages can be signed directly; thus the hash of a
    88  	// message, rather than the message itself, is signed. This requires
    89  	// that the hash function be collision resistant. SHA-256 is the
    90  	// least-strong hash function that should be used for this at the time
    91  	// of writing (2016).
    92  	hashed := sha256.Sum256(message)
    93  
    94  	signature, err := rsa.SignPKCS1v15(nil, rsaPrivateKey, crypto.SHA256, hashed[:])
    95  	if err != nil {
    96  		fmt.Fprintf(os.Stderr, "Error from signing: %s\n", err)
    97  		return
    98  	}
    99  
   100  	fmt.Printf("Signature: %x\n", signature)
   101  }
   102  
   103  func ExampleVerifyPKCS1v15() {
   104  	message := []byte("message to be signed")
   105  	signature, _ := hex.DecodeString("ad2766728615cc7a746cc553916380ca7bfa4f8983b990913bc69eb0556539a350ff0f8fe65ddfd3ebe91fe1c299c2fac135bc8c61e26be44ee259f2f80c1530")
   106  
   107  	// Only small messages can be signed directly; thus the hash of a
   108  	// message, rather than the message itself, is signed. This requires
   109  	// that the hash function be collision resistant. SHA-256 is the
   110  	// least-strong hash function that should be used for this at the time
   111  	// of writing (2016).
   112  	hashed := sha256.Sum256(message)
   113  
   114  	err := rsa.VerifyPKCS1v15(&rsaPrivateKey.PublicKey, crypto.SHA256, hashed[:], signature)
   115  	if err != nil {
   116  		fmt.Fprintf(os.Stderr, "Error from verification: %s\n", err)
   117  		return
   118  	}
   119  
   120  	// signature is a valid signature of message from the public key.
   121  }
   122  
   123  func ExampleEncryptOAEP() {
   124  	secretMessage := []byte("send reinforcements, we're going to advance")
   125  	label := []byte("orders")
   126  
   127  	// crypto/rand.Reader is a good source of entropy for randomizing the
   128  	// encryption function.
   129  	rng := rand.Reader
   130  
   131  	ciphertext, err := rsa.EncryptOAEP(sha256.New(), rng, &test2048Key.PublicKey, secretMessage, label)
   132  	if err != nil {
   133  		fmt.Fprintf(os.Stderr, "Error from encryption: %s\n", err)
   134  		return
   135  	}
   136  
   137  	// Since encryption is a randomized function, ciphertext will be
   138  	// different each time.
   139  	fmt.Printf("Ciphertext: %x\n", ciphertext)
   140  }
   141  
   142  func ExampleDecryptOAEP() {
   143  	ciphertext, _ := hex.DecodeString("4d1ee10e8f286390258c51a5e80802844c3e6358ad6690b7285218a7c7ed7fc3a4c7b950fbd04d4b0239cc060dcc7065ca6f84c1756deb71ca5685cadbb82be025e16449b905c568a19c088a1abfad54bf7ecc67a7df39943ec511091a34c0f2348d04e058fcff4d55644de3cd1d580791d4524b92f3e91695582e6e340a1c50b6c6d78e80b4e42c5b4d45e479b492de42bbd39cc642ebb80226bb5200020d501b24a37bcc2ec7f34e596b4fd6b063de4858dbf5a4e3dd18e262eda0ec2d19dbd8e890d672b63d368768360b20c0b6b8592a438fa275e5fa7f60bef0dd39673fd3989cc54d2cb80c08fcd19dacbc265ee1c6014616b0e04ea0328c2a04e73460")
   144  	label := []byte("orders")
   145  
   146  	plaintext, err := rsa.DecryptOAEP(sha256.New(), nil, test2048Key, ciphertext, label)
   147  	if err != nil {
   148  		fmt.Fprintf(os.Stderr, "Error from decryption: %s\n", err)
   149  		return
   150  	}
   151  
   152  	fmt.Printf("Plaintext: %s\n", plaintext)
   153  
   154  	// Remember that encryption only provides confidentiality. The
   155  	// ciphertext should be signed before authenticity is assumed and, even
   156  	// then, consider that messages might be reordered.
   157  }
   158  

View as plain text