Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(527)

Delta Between Two Patch Sets: src/pkg/crypto/x509/pem_decrypt.go

Issue 6820114: code review 6820114: crypto/x509: implement EncryptPEMBlock (Closed)
Left Patch Set: diff -r b661b713984f https://go.googlecode.com/hg/ Created 11 years, 4 months ago
Right Patch Set: diff -r 4e14b1d8a88d https://go.googlecode.com/hg/ Created 11 years, 4 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | src/pkg/crypto/x509/pem_decrypt_test.go » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
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
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
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 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b