-
Notifications
You must be signed in to change notification settings - Fork 23
/
cipher_rc5_cbc.go
162 lines (126 loc) · 3.7 KB
/
cipher_rc5_cbc.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
package pbes2
import (
"io"
"errors"
"crypto/cipher"
"encoding/asn1"
)
// cbc 模式加密参数
type rc5CBCParams struct {
WordSize int
Rounds int
IV []byte
}
// cbc 模式加密
type CipherRC5CBC struct {
cipherFunc func(key []byte, wordSize, r uint) (cipher.Block, error)
wordSize uint
rounds uint
keySize int
identifier asn1.ObjectIdentifier
hasKeyLength bool
needBmpPass bool
}
// 值大小
func (this CipherRC5CBC) KeySize() int {
return this.keySize
}
// oid
func (this CipherRC5CBC) OID() asn1.ObjectIdentifier {
return this.identifier
}
// 是否有 KeyLength
func (this CipherRC5CBC) HasKeyLength() bool {
return this.hasKeyLength
}
// 密码是否需要 Bmp 处理
func (this CipherRC5CBC) NeedBmpPassword() bool {
return this.needBmpPass
}
// 加密
func (this CipherRC5CBC) Encrypt(rand io.Reader, key, plaintext []byte) ([]byte, []byte, error) {
block, err := this.cipherFunc(key, this.wordSize, this.rounds)
if err != nil {
return nil, nil, errors.New("pkcs/cipher: failed to create cipher: " + err.Error())
}
blockSize := block.BlockSize()
// 随机生成 iv
iv := make([]byte, blockSize)
if _, err := io.ReadFull(rand, iv); err != nil {
return nil, nil, errors.New("pkcs/cipher: failed to generate IV: " + err.Error())
}
// 加密数据补码
plaintext = pkcs7Padding(plaintext, blockSize)
// 需要保存的加密数据
encrypted := make([]byte, len(plaintext))
enc := cipher.NewCBCEncrypter(block, iv)
enc.CryptBlocks(encrypted, plaintext)
// 需要编码的参数
paramSeq := rc5CBCParams{
WordSize: int(this.wordSize),
Rounds: int(this.rounds),
IV: iv,
}
// 编码
paramBytes, err := asn1.Marshal(paramSeq)
if err != nil {
return nil, nil, err
}
return encrypted, paramBytes, nil
}
// 解密
func (this CipherRC5CBC) Decrypt(key, params, ciphertext []byte) ([]byte, error) {
// 解析参数
var param rc5CBCParams
if _, err := asn1.Unmarshal(params, ¶m); err != nil {
return nil, errors.New("pkcs/cipher: invalid parameters")
}
block, err := this.cipherFunc(key, uint(param.WordSize), uint(param.Rounds))
if err != nil {
return nil, err
}
blockSize := block.BlockSize()
if len(param.IV) != blockSize {
return nil, errors.New("pkcs/cipher: incorrect IV size")
}
if len(ciphertext)%blockSize != 0 {
return nil, errors.New("pkcs/cipher: encrypted PEM data is not a multiple of the block size")
}
plaintext := make([]byte, len(ciphertext))
mode := cipher.NewCBCDecrypter(block, param.IV)
mode.CryptBlocks(plaintext, ciphertext)
// 判断数据是否为填充数据
dlen := len(plaintext)
if dlen == 0 || dlen%blockSize != 0 {
return nil, errors.New("pkcs/cipher: invalid padding")
}
// 解析加密数据
pt, err := pkcs7UnPadding(plaintext)
if err != nil {
return plaintext, nil
}
return pt, nil
}
// 设置 WordSize
func (this CipherRC5CBC) WithWordSize(wordSize uint) CipherRC5CBC {
this.wordSize = wordSize
return this
}
// 设置 Rounds
func (this CipherRC5CBC) WithRounds(rounds uint) CipherRC5CBC {
this.rounds = rounds
return this
}
// 设置 keySize
func (this CipherRC5CBC) WithKeySize(keySize int) CipherRC5CBC {
this.keySize = keySize
return this
}
func (this CipherRC5CBC) WithHasKeyLength(hasKeyLength bool) CipherRC5CBC {
this.hasKeyLength = hasKeyLength
return this
}
func (this CipherRC5CBC) WithNeedBmpPassword(needBmpPass bool) CipherRC5CBC {
this.needBmpPass = needBmpPass
return this
}