1
2
3
4
5 package des
6
7 import (
8 "encoding/binary"
9 "sync"
10 )
11
12 func cryptBlock(subkeys []uint64, dst, src []byte, decrypt bool) {
13 b := binary.BigEndian.Uint64(src)
14 b = permuteInitialBlock(b)
15 left, right := uint32(b>>32), uint32(b)
16
17 left = (left << 1) | (left >> 31)
18 right = (right << 1) | (right >> 31)
19
20 if decrypt {
21 for i := 0; i < 8; i++ {
22 left, right = feistel(left, right, subkeys[15-2*i], subkeys[15-(2*i+1)])
23 }
24 } else {
25 for i := 0; i < 8; i++ {
26 left, right = feistel(left, right, subkeys[2*i], subkeys[2*i+1])
27 }
28 }
29
30 left = (left << 31) | (left >> 1)
31 right = (right << 31) | (right >> 1)
32
33
34 preOutput := (uint64(right) << 32) | uint64(left)
35 binary.BigEndian.PutUint64(dst, permuteFinalBlock(preOutput))
36 }
37
38
39 func encryptBlock(subkeys []uint64, dst, src []byte) {
40 cryptBlock(subkeys, dst, src, false)
41 }
42
43
44 func decryptBlock(subkeys []uint64, dst, src []byte) {
45 cryptBlock(subkeys, dst, src, true)
46 }
47
48
49
50 func feistel(l, r uint32, k0, k1 uint64) (lout, rout uint32) {
51 var t uint32
52
53 t = r ^ uint32(k0>>32)
54 l ^= feistelBox[7][t&0x3f] ^
55 feistelBox[5][(t>>8)&0x3f] ^
56 feistelBox[3][(t>>16)&0x3f] ^
57 feistelBox[1][(t>>24)&0x3f]
58
59 t = ((r << 28) | (r >> 4)) ^ uint32(k0)
60 l ^= feistelBox[6][(t)&0x3f] ^
61 feistelBox[4][(t>>8)&0x3f] ^
62 feistelBox[2][(t>>16)&0x3f] ^
63 feistelBox[0][(t>>24)&0x3f]
64
65 t = l ^ uint32(k1>>32)
66 r ^= feistelBox[7][t&0x3f] ^
67 feistelBox[5][(t>>8)&0x3f] ^
68 feistelBox[3][(t>>16)&0x3f] ^
69 feistelBox[1][(t>>24)&0x3f]
70
71 t = ((l << 28) | (l >> 4)) ^ uint32(k1)
72 r ^= feistelBox[6][(t)&0x3f] ^
73 feistelBox[4][(t>>8)&0x3f] ^
74 feistelBox[2][(t>>16)&0x3f] ^
75 feistelBox[0][(t>>24)&0x3f]
76
77 return l, r
78 }
79
80
81
82 var feistelBox [8][64]uint32
83
84 var feistelBoxOnce sync.Once
85
86
87 func permuteBlock(src uint64, permutation []uint8) (block uint64) {
88 for position, n := range permutation {
89 bit := (src >> n) & 1
90 block |= bit << uint((len(permutation)-1)-position)
91 }
92 return
93 }
94
95 func initFeistelBox() {
96 for s := range sBoxes {
97 for i := 0; i < 4; i++ {
98 for j := 0; j < 16; j++ {
99 f := uint64(sBoxes[s][i][j]) << (4 * (7 - uint(s)))
100 f = permuteBlock(f, permutationFunction[:])
101
102
103
104 row := uint8(((i & 2) << 4) | i&1)
105 col := uint8(j << 1)
106 t := row | col
107
108
109 f = (f << 1) | (f >> 31)
110
111 feistelBox[s][t] = uint32(f)
112 }
113 }
114 }
115 }
116
117
118
119 func permuteInitialBlock(block uint64) uint64 {
120
121 b1 := block >> 48
122 b2 := block << 48
123 block ^= b1 ^ b2 ^ b1<<48 ^ b2>>48
124
125
126 b1 = block >> 32 & 0xff00ff
127 b2 = (block & 0xff00ff00)
128 block ^= b1<<32 ^ b2 ^ b1<<8 ^ b2<<24
129
130
131
132
133
134
135
136
137
138
139
140
141 b1 = block & 0x0f0f00000f0f0000
142 b2 = block & 0x0000f0f00000f0f0
143 block ^= b1 ^ b2 ^ b1>>12 ^ b2<<12
144
145
146
147
148
149
150
151
152
153
154
155 b1 = block & 0x3300330033003300
156 b2 = block & 0x00cc00cc00cc00cc
157 block ^= b1 ^ b2 ^ b1>>6 ^ b2<<6
158
159
160
161
162
163
164
165
166
167
168
169
170 b1 = block & 0xaaaaaaaa55555555
171 block ^= b1 ^ b1>>33 ^ b1<<33
172
173
174
175
176
177
178
179
180
181
182 return block
183 }
184
185
186
187 func permuteFinalBlock(block uint64) uint64 {
188
189
190 b1 := block & 0xaaaaaaaa55555555
191 block ^= b1 ^ b1>>33 ^ b1<<33
192
193 b1 = block & 0x3300330033003300
194 b2 := block & 0x00cc00cc00cc00cc
195 block ^= b1 ^ b2 ^ b1>>6 ^ b2<<6
196
197 b1 = block & 0x0f0f00000f0f0000
198 b2 = block & 0x0000f0f00000f0f0
199 block ^= b1 ^ b2 ^ b1>>12 ^ b2<<12
200
201 b1 = block >> 32 & 0xff00ff
202 b2 = (block & 0xff00ff00)
203 block ^= b1<<32 ^ b2 ^ b1<<8 ^ b2<<24
204
205 b1 = block >> 48
206 b2 = block << 48
207 block ^= b1 ^ b2 ^ b1<<48 ^ b2>>48
208 return block
209 }
210
211
212
213 func ksRotate(in uint32) (out []uint32) {
214 out = make([]uint32, 16)
215 last := in
216 for i := 0; i < 16; i++ {
217
218 left := (last << (4 + ksRotations[i])) >> 4
219 right := (last << 4) >> (32 - ksRotations[i])
220 out[i] = left | right
221 last = out[i]
222 }
223 return
224 }
225
226
227 func (c *desCipher) generateSubkeys(keyBytes []byte) {
228 feistelBoxOnce.Do(initFeistelBox)
229
230
231 key := binary.BigEndian.Uint64(keyBytes)
232 permutedKey := permuteBlock(key, permutedChoice1[:])
233
234
235 leftRotations := ksRotate(uint32(permutedKey >> 28))
236 rightRotations := ksRotate(uint32(permutedKey<<4) >> 4)
237
238
239 for i := 0; i < 16; i++ {
240
241 pc2Input := uint64(leftRotations[i])<<28 | uint64(rightRotations[i])
242
243 c.subkeys[i] = unpack(permuteBlock(pc2Input, permutedChoice2[:]))
244 }
245 }
246
247
248
249
250 func unpack(x uint64) uint64 {
251 var result uint64
252
253 result = ((x>>(6*1))&0xff)<<(8*0) |
254 ((x>>(6*3))&0xff)<<(8*1) |
255 ((x>>(6*5))&0xff)<<(8*2) |
256 ((x>>(6*7))&0xff)<<(8*3) |
257 ((x>>(6*0))&0xff)<<(8*4) |
258 ((x>>(6*2))&0xff)<<(8*5) |
259 ((x>>(6*4))&0xff)<<(8*6) |
260 ((x>>(6*6))&0xff)<<(8*7)
261
262 return result
263 }
264
View as plain text