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
5package rsa
6
7import (
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.
38func 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
88func 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
111func 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
131func 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
150func 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