Home | History | Annotate | Download | only in rsa
      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
      6 
      7 import (
      8 	"crypto"
      9 	"crypto/aes"
     10 	"crypto/cipher"
     11 	"crypto/rand"
     12 	"crypto/sha256"
     13 	"encoding/hex"
     14 	"fmt"
     15 	"io"
     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 	// crypto/rand.Reader is a good source of entropy for blinding the RSA
     40 	// operation.
     41 	rng := rand.Reader
     42 
     43 	// The hybrid scheme should use at least a 16-byte symmetric key. Here
     44 	// we read the random key that will be used if the RSA decryption isn't
     45 	// well-formed.
     46 	key := make([]byte, 32)
     47 	if _, err := io.ReadFull(rng, key); err != nil {
     48 		panic("RNG failure")
     49 	}
     50 
     51 	rsaCiphertext, _ := hex.DecodeString("aabbccddeeff")
     52 
     53 	if err := DecryptPKCS1v15SessionKey(rng, rsaPrivateKey, rsaCiphertext, key); err != nil {
     54 		// Any errors that result will be public  meaning that they
     55 		// can be determined without any secret information. (For
     56 		// instance, if the length of key is impossible given the RSA
     57 		// public key.)
     58 		fmt.Fprintf(os.Stderr, "Error from RSA decryption: %s\n", err)
     59 		return
     60 	}
     61 
     62 	// Given the resulting key, a symmetric scheme can be used to decrypt a
     63 	// larger ciphertext.
     64 	block, err := aes.NewCipher(key)
     65 	if err != nil {
     66 		panic("aes.NewCipher failed: " + err.Error())
     67 	}
     68 
     69 	// Since the key is random, using a fixed nonce is acceptable as the
     70 	// (key, nonce) pair will still be unique, as required.
     71 	var zeroNonce [12]byte
     72 	aead, err := cipher.NewGCM(block)
     73 	if err != nil {
     74 		panic("cipher.NewGCM failed: " + err.Error())
     75 	}
     76 	ciphertext, _ := hex.DecodeString("00112233445566")
     77 	plaintext, err := aead.Open(nil, zeroNonce[:], ciphertext, nil)
     78 	if err != nil {
     79 		// The RSA ciphertext was badly formed; the decryption will
     80 		// fail here because the AES-GCM key will be incorrect.
     81 		fmt.Fprintf(os.Stderr, "Error decrypting: %s\n", err)
     82 		return
     83 	}
     84 
     85 	fmt.Printf("Plaintext: %s\n", string(plaintext))
     86 }
     87 
     88 func ExampleSignPKCS1v15() {
     89 	// crypto/rand.Reader is a good source of entropy for blinding the RSA
     90 	// operation.
     91 	rng := rand.Reader
     92 
     93 	message := []byte("message to be signed")
     94 
     95 	// Only small messages can be signed directly; thus the hash of a
     96 	// message, rather than the message itself, is signed. This requires
     97 	// that the hash function be collision resistant. SHA-256 is the
     98 	// least-strong hash function that should be used for this at the time
     99 	// of writing (2016).
    100 	hashed := sha256.Sum256(message)
    101 
    102 	signature, err := SignPKCS1v15(rng, rsaPrivateKey, crypto.SHA256, hashed[:])
    103 	if err != nil {
    104 		fmt.Fprintf(os.Stderr, "Error from signing: %s\n", err)
    105 		return
    106 	}
    107 
    108 	fmt.Printf("Signature: %x\n", signature)
    109 }
    110 
    111 func ExampleVerifyPKCS1v15() {
    112 	message := []byte("message to be signed")
    113 	signature, _ := hex.DecodeString("ad2766728615cc7a746cc553916380ca7bfa4f8983b990913bc69eb0556539a350ff0f8fe65ddfd3ebe91fe1c299c2fac135bc8c61e26be44ee259f2f80c1530")
    114 
    115 	// Only small messages can be signed directly; thus the hash of a
    116 	// message, rather than the message itself, is signed. This requires
    117 	// that the hash function be collision resistant. SHA-256 is the
    118 	// least-strong hash function that should be used for this at the time
    119 	// of writing (2016).
    120 	hashed := sha256.Sum256(message)
    121 
    122 	err := VerifyPKCS1v15(&rsaPrivateKey.PublicKey, crypto.SHA256, hashed[:], signature)
    123 	if err != nil {
    124 		fmt.Fprintf(os.Stderr, "Error from verification: %s\n", err)
    125 		return
    126 	}
    127 
    128 	// signature is a valid signature of message from the public key.
    129 }
    130 
    131 func ExampleEncryptOAEP() {
    132 	secretMessage := []byte("send reinforcements, we're going to advance")
    133 	label := []byte("orders")
    134 
    135 	// crypto/rand.Reader is a good source of entropy for randomizing the
    136 	// encryption function.
    137 	rng := rand.Reader
    138 
    139 	ciphertext, err := EncryptOAEP(sha256.New(), rng, &test2048Key.PublicKey, secretMessage, label)
    140 	if err != nil {
    141 		fmt.Fprintf(os.Stderr, "Error from encryption: %s\n", err)
    142 		return
    143 	}
    144 
    145 	// Since encryption is a randomized function, ciphertext will be
    146 	// different each time.
    147 	fmt.Printf("Ciphertext: %x\n", ciphertext)
    148 }
    149 
    150 func ExampleDecryptOAEP() {
    151 	ciphertext, _ := hex.DecodeString("4d1ee10e8f286390258c51a5e80802844c3e6358ad6690b7285218a7c7ed7fc3a4c7b950fbd04d4b0239cc060dcc7065ca6f84c1756deb71ca5685cadbb82be025e16449b905c568a19c088a1abfad54bf7ecc67a7df39943ec511091a34c0f2348d04e058fcff4d55644de3cd1d580791d4524b92f3e91695582e6e340a1c50b6c6d78e80b4e42c5b4d45e479b492de42bbd39cc642ebb80226bb5200020d501b24a37bcc2ec7f34e596b4fd6b063de4858dbf5a4e3dd18e262eda0ec2d19dbd8e890d672b63d368768360b20c0b6b8592a438fa275e5fa7f60bef0dd39673fd3989cc54d2cb80c08fcd19dacbc265ee1c6014616b0e04ea0328c2a04e73460")
    152 	label := []byte("orders")
    153 
    154 	// crypto/rand.Reader is a good source of entropy for blinding the RSA
    155 	// operation.
    156 	rng := rand.Reader
    157 
    158 	plaintext, err := DecryptOAEP(sha256.New(), rng, test2048Key, ciphertext, label)
    159 	if err != nil {
    160 		fmt.Fprintf(os.Stderr, "Error from decryption: %s\n", err)
    161 		return
    162 	}
    163 
    164 	fmt.Printf("Plaintext: %s\n", string(plaintext))
    165 
    166 	// Remember that encryption only provides confidentiality. The
    167 	// ciphertext should be signed before authenticity is assumed and, even
    168 	// then, consider that messages might be reordered.
    169 }
    170