LEFT | RIGHT |
1 // Copyright 2012 The Go Authors. All rights reserved. | 1 // Copyright 2012 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 package x509 | 5 package x509 |
6 | 6 |
7 // RFC 1423 describes the encryption of PEM blocks. The algorithm used to | 7 // RFC 1423 describes the encryption of PEM blocks. The algorithm used to |
8 // generate a key from the password was derived by looking at the OpenSSL | 8 // generate a key from the password was derived by looking at the OpenSSL |
9 // implementation. | 9 // implementation. |
10 | 10 |
11 import ( | 11 import ( |
12 "crypto/aes" | 12 "crypto/aes" |
13 "crypto/cipher" | 13 "crypto/cipher" |
14 "crypto/des" | 14 "crypto/des" |
15 "crypto/md5" | 15 "crypto/md5" |
16 "encoding/hex" | 16 "encoding/hex" |
17 "encoding/pem" | 17 "encoding/pem" |
18 "errors" | 18 "errors" |
19 "io" | 19 "io" |
20 "strings" | 20 "strings" |
21 ) | 21 ) |
22 | 22 |
23 // rfc1423Algos represents how to create a block cipher for a decryption mode. | 23 type PEMCipher int |
| 24 |
| 25 // Possible values for the EncryptPEMBlock encryption algorithm. |
| 26 const ( |
| 27 » _ PEMCipher = iota |
| 28 » PEMCipherDES |
| 29 » PEMCipher3DES |
| 30 » PEMCipherAES128 |
| 31 » PEMCipherAES192 |
| 32 » PEMCipherAES256 |
| 33 ) |
| 34 |
| 35 // rfc1423Algo holds a method for enciphering a PEM block. |
24 type rfc1423Algo struct { | 36 type rfc1423Algo struct { |
25 » cipherFunc func([]byte) (cipher.Block, error) | 37 » cipher PEMCipher |
| 38 » name string |
| 39 » cipherFunc func(key []byte) (cipher.Block, error) |
26 keySize int | 40 keySize int |
27 blockSize int | 41 blockSize int |
28 } | 42 } |
29 | 43 |
30 // rfc1423Algos is a mapping of encryption algorithm to an rfc1423Algo that can | 44 // rfc1423Algos holds a slice of the possible ways to encrypt a PEM |
31 // create block ciphers for that mode. | 45 // block. The ivSize numbers were taken from the OpenSSL source. |
32 // The ivSize numbers were taken from the OpenSSL source. | 46 var rfc1423Algos = []rfc1423Algo{{ |
33 var rfc1423Algos = map[string]rfc1423Algo{ | 47 » cipher: PEMCipherDES, |
34 » "DES-CBC": {des.NewCipher, 8, des.BlockSize}, | 48 » name: "DES-CBC", |
35 » "DES-EDE3-CBC": {des.NewTripleDESCipher, 24, des.BlockSize}, | 49 » cipherFunc: des.NewCipher, |
36 » "AES-128-CBC": {aes.NewCipher, 16, aes.BlockSize}, | 50 » keySize: 8, |
37 » "AES-192-CBC": {aes.NewCipher, 24, aes.BlockSize}, | 51 » blockSize: des.BlockSize, |
38 » "AES-256-CBC": {aes.NewCipher, 32, aes.BlockSize}, | 52 }, { |
| 53 » cipher: PEMCipher3DES, |
| 54 » name: "DES-EDE3-CBC", |
| 55 » cipherFunc: des.NewTripleDESCipher, |
| 56 » keySize: 24, |
| 57 » blockSize: des.BlockSize, |
| 58 }, { |
| 59 » cipher: PEMCipherAES128, |
| 60 » name: "AES-128-CBC", |
| 61 » cipherFunc: aes.NewCipher, |
| 62 » keySize: 16, |
| 63 » blockSize: aes.BlockSize, |
| 64 }, { |
| 65 » cipher: PEMCipherAES192, |
| 66 » name: "AES-192-CBC", |
| 67 » cipherFunc: aes.NewCipher, |
| 68 » keySize: 24, |
| 69 » blockSize: aes.BlockSize, |
| 70 }, { |
| 71 » cipher: PEMCipherAES256, |
| 72 » name: "AES-256-CBC", |
| 73 » cipherFunc: aes.NewCipher, |
| 74 » keySize: 32, |
| 75 » blockSize: aes.BlockSize, |
| 76 }, |
39 } | 77 } |
40 | 78 |
41 // deriveKey uses a key derivation function to stretch the password into a key | 79 // deriveKey uses a key derivation function to stretch the password into a key |
42 // with the number of bits our cipher requires. This algorithm was derived from | 80 // with the number of bits our cipher requires. This algorithm was derived from |
43 // the OpenSSL source. | 81 // the OpenSSL source. |
44 func (c rfc1423Algo) deriveKey(password, salt []byte) []byte { | 82 func (c rfc1423Algo) deriveKey(password, salt []byte) []byte { |
45 hash := md5.New() | 83 hash := md5.New() |
46 out := make([]byte, c.keySize) | 84 out := make([]byte, c.keySize) |
47 var digest []byte | 85 var digest []byte |
48 | 86 |
(...skipping 27 matching lines...) Expand all Loading... |
76 if !ok { | 114 if !ok { |
77 return nil, errors.New("x509: no DEK-Info header in block") | 115 return nil, errors.New("x509: no DEK-Info header in block") |
78 } | 116 } |
79 | 117 |
80 idx := strings.Index(dek, ",") | 118 idx := strings.Index(dek, ",") |
81 if idx == -1 { | 119 if idx == -1 { |
82 return nil, errors.New("x509: malformed DEK-Info header") | 120 return nil, errors.New("x509: malformed DEK-Info header") |
83 } | 121 } |
84 | 122 |
85 mode, hexIV := dek[:idx], dek[idx+1:] | 123 mode, hexIV := dek[:idx], dek[idx+1:] |
86 » ciph, ok := rfc1423Algos[mode] | 124 » ciph := cipherByName(mode) |
87 » if !ok { | 125 » if ciph == nil { |
88 return nil, errors.New("x509: unknown encryption mode") | 126 return nil, errors.New("x509: unknown encryption mode") |
89 } | 127 } |
90 iv, err := hex.DecodeString(hexIV) | 128 iv, err := hex.DecodeString(hexIV) |
91 if err != nil { | 129 if err != nil { |
92 return nil, err | 130 return nil, err |
93 } | 131 } |
94 if len(iv) != ciph.blockSize { | 132 if len(iv) != ciph.blockSize { |
95 » » return nil, errors.New("x509: wrong IV size") | 133 » » return nil, errors.New("x509: incorrect IV size") |
96 } | 134 } |
97 | 135 |
98 // Based on the OpenSSL implementation. The salt is the first 8 bytes | 136 // Based on the OpenSSL implementation. The salt is the first 8 bytes |
99 // of the initialization vector. | 137 // of the initialization vector. |
100 key := ciph.deriveKey(password, iv[:8]) | 138 key := ciph.deriveKey(password, iv[:8]) |
101 block, err := ciph.cipherFunc(key) | 139 block, err := ciph.cipherFunc(key) |
102 if err != nil { | 140 if err != nil { |
103 return nil, err | 141 return nil, err |
104 } | 142 } |
105 | 143 |
(...skipping 21 matching lines...) Expand all Loading... |
127 for _, val := range data[dlen-last:] { | 165 for _, val := range data[dlen-last:] { |
128 if int(val) != last { | 166 if int(val) != last { |
129 return nil, IncorrectPasswordError | 167 return nil, IncorrectPasswordError |
130 } | 168 } |
131 } | 169 } |
132 return data[:dlen-last], nil | 170 return data[:dlen-last], nil |
133 } | 171 } |
134 | 172 |
135 // EncryptPEMBlock returns a PEM block of the specified type holding the | 173 // EncryptPEMBlock returns a PEM block of the specified type holding the |
136 // given DER-encoded data encrypted with the specified algorithm and | 174 // given DER-encoded data encrypted with the specified algorithm and |
137 // password. The algorithm, alg, must be one of the following strings: | 175 // password. |
138 // | 176 func EncryptPEMBlock(rand io.Reader, blockType string, data, password []byte, al
g PEMCipher) (*pem.Block, error) { |
139 // » "DES-CBC" | 177 » ciph := cipherByKey(alg) |
140 //» "DES-EDE3-CBC" | 178 » if ciph == nil { |
141 //» "AES-128-CBC" | |
142 //» "AES-192-CBC" | |
143 //» "AES-256-CBC" | |
144 // | |
145 func EncryptPEMBlock(blockType string, rand io.Reader, data, password []byte, al
g string) (*pem.Block, error) { | |
146 » ciph, ok := rfc1423Algos[alg] | |
147 » if !ok { | |
148 return nil, errors.New("x509: unknown encryption mode") | 179 return nil, errors.New("x509: unknown encryption mode") |
149 } | 180 } |
150 iv := make([]byte, ciph.blockSize) | 181 iv := make([]byte, ciph.blockSize) |
151 if _, err := io.ReadFull(rand, iv); err != nil { | 182 if _, err := io.ReadFull(rand, iv); err != nil { |
152 » » return nil, errors.New("cannot generate IV: " + err.Error()) | 183 » » return nil, errors.New("x509: cannot generate IV: " + err.Error(
)) |
153 » } | 184 » } |
| 185 » // The salt is the first 8 bytes of the initialization vector, |
| 186 » // matching the key derivation in DecryptPEMBlock. |
154 key := ciph.deriveKey(password, iv[:8]) | 187 key := ciph.deriveKey(password, iv[:8]) |
155 block, err := ciph.cipherFunc(key) | 188 block, err := ciph.cipherFunc(key) |
156 if err != nil { | 189 if err != nil { |
157 return nil, err | 190 return nil, err |
158 } | 191 } |
159 » dec := cipher.NewCBCEncrypter(block, iv) | 192 » enc := cipher.NewCBCEncrypter(block, iv) |
160 pad := ciph.blockSize - len(data)%ciph.blockSize | 193 pad := ciph.blockSize - len(data)%ciph.blockSize |
161 encrypted := make([]byte, len(data), len(data)+pad) | 194 encrypted := make([]byte, len(data), len(data)+pad) |
162 // We could save this copy by encrypting all the whole blocks in | 195 // We could save this copy by encrypting all the whole blocks in |
163 // the data separately, but it doesn't seem worth the additional | 196 // the data separately, but it doesn't seem worth the additional |
164 // code. | 197 // code. |
165 copy(encrypted, data) | 198 copy(encrypted, data) |
166 // See RFC 1423, section 1.1 | 199 // See RFC 1423, section 1.1 |
167 for i := 0; i < pad; i++ { | 200 for i := 0; i < pad; i++ { |
168 encrypted = append(encrypted, byte(pad)) | 201 encrypted = append(encrypted, byte(pad)) |
169 } | 202 } |
170 » dec.CryptBlocks(encrypted, encrypted) | 203 » enc.CryptBlocks(encrypted, encrypted) |
171 | 204 |
172 return &pem.Block{ | 205 return &pem.Block{ |
173 Type: blockType, | 206 Type: blockType, |
174 Headers: map[string]string{ | 207 Headers: map[string]string{ |
175 "Proc-Type": "4,ENCRYPTED", | 208 "Proc-Type": "4,ENCRYPTED", |
176 » » » "DEK-Info": alg + "," + hex.EncodeToString(iv), | 209 » » » "DEK-Info": ciph.name + "," + hex.EncodeToString(iv), |
177 }, | 210 }, |
178 Bytes: encrypted, | 211 Bytes: encrypted, |
179 }, nil | 212 }, nil |
180 } | 213 } |
| 214 |
| 215 func cipherByName(name string) *rfc1423Algo { |
| 216 for i := range rfc1423Algos { |
| 217 alg := &rfc1423Algos[i] |
| 218 if alg.name == name { |
| 219 return alg |
| 220 } |
| 221 } |
| 222 return nil |
| 223 } |
| 224 |
| 225 func cipherByKey(key PEMCipher) *rfc1423Algo { |
| 226 for i := range rfc1423Algos { |
| 227 alg := &rfc1423Algos[i] |
| 228 if alg.cipher == key { |
| 229 return alg |
| 230 } |
| 231 } |
| 232 return nil |
| 233 } |
LEFT | RIGHT |