Skip to content

Commit 1aec7c7

Browse files
Berengar Lehragl
Berengar Lehr
authored andcommitted
crypto: add twofish package
The code was (as annotated in the source code) adopted from Tom's LibCrypt (public domain code, [1]). It was neither optimised for speed nor were any security features added. [1] http://libtom.org/?page=features&newsitems=5&whatfile=crypt R=rsc, berengarlehr, albert.strasheim, agl1 CC=golang-dev, schulze https://golang.org/cl/2687042
1 parent 1c99bdc commit 1aec7c7

File tree

5 files changed

+500
-0
lines changed

5 files changed

+500
-0
lines changed

CONTRIBUTORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ Corey Thomasson <[email protected]>
6868
Dan Sinclair <[email protected]>
6969
Daniel Fleischman <[email protected]>
7070
Daniel Nadasi <[email protected]>
71+
Berengar Lehr <[email protected]>
7172
Daniel Theophanes <[email protected]>
7273
David G. Andersen <[email protected]>
7374
David Symonds <[email protected]>

src/pkg/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ DIRS=\
4747
crypto/sha512\
4848
crypto/subtle\
4949
crypto/tls\
50+
crypto/twofish\
5051
crypto/x509\
5152
crypto/xtea\
5253
debug/dwarf\

src/pkg/crypto/twofish/Makefile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Copyright 2011 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+
5+
include ../../../Make.inc
6+
7+
TARG=crypto/twofish
8+
GOFILES=\
9+
twofish.go\
10+
11+
include ../../../Make.pkg

src/pkg/crypto/twofish/twofish.go

Lines changed: 358 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,358 @@
1+
// Copyright 2011 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+
5+
// This package implements Bruce Schneier's Twofish encryption algorithm.
6+
package twofish
7+
8+
// Twofish is defined in http://www.schneier.com/paper-twofish-paper.pdf [TWOFISH]
9+
10+
// This code is a port of the LibTom C implementation.
11+
// See http://libtom.org/?page=features&newsitems=5&whatfile=crypt.
12+
// LibTomCrypt is free for all purposes under the public domain.
13+
// It was heavily inspired by the go blowfish package.
14+
15+
import (
16+
"os"
17+
"strconv"
18+
)
19+
20+
// BlockSize is the constant block size of Twofish.
21+
const BlockSize = 16
22+
23+
const mdsPolynomial = 0x169 // x^8 + x^6 + x^5 + x^3 + 1, see [TWOFISH] 4.2
24+
const rsPolynomial = 0x14d // x^8 + x^6 + x^3 + x^2 + 1, see [TWOFISH] 4.3
25+
26+
// A Cipher is an instance of Twofish encryption using a particular key.
27+
type Cipher struct {
28+
s [4][256]uint32
29+
k [40]uint32
30+
}
31+
32+
type KeySizeError int
33+
34+
func (k KeySizeError) String() string {
35+
return "crypto/twofish: invalid key size " + strconv.Itoa(int(k))
36+
}
37+
38+
// NewCipher creates and returns a Cipher.
39+
// The key argument should be the Twofish key, 16, 24 or 32 bytes.
40+
func NewCipher(key []byte) (*Cipher, os.Error) {
41+
keylen := len(key)
42+
43+
if keylen != 16 && keylen != 24 && keylen != 32 {
44+
return nil, KeySizeError(keylen)
45+
}
46+
47+
// k is the number of 64 bit words in key
48+
k := keylen / 8
49+
50+
// Create the S[..] words
51+
var S [4 * 4]byte
52+
for i := 0; i < k; i++ {
53+
// Computes [y0 y1 y2 y3] = rs . [x0 x1 x2 x3 x4 x5 x6 x7]
54+
for j := 0; j < 4; j++ {
55+
for k := 0; k < 8; k++ {
56+
S[4*i+j] ^= gfMult(key[8*i+k], rs[j][k], rsPolynomial)
57+
}
58+
}
59+
}
60+
61+
// Calculate subkeys
62+
c := new(Cipher)
63+
var tmp [4]byte
64+
for i := byte(0); i < 20; i++ {
65+
// A = h(p * 2x, Me)
66+
for j := 0; j < 4; j++ {
67+
tmp[j] = 2 * i
68+
}
69+
A := h(tmp[:], key, 0)
70+
71+
// B = rolc(h(p * (2x + 1), Mo), 8)
72+
for j := 0; j < 4; j++ {
73+
tmp[j] = 2*i + 1
74+
}
75+
B := h(tmp[:], key, 1)
76+
B = rol(B, 8)
77+
78+
c.k[2*i] = A + B
79+
80+
// K[2i+1] = (A + 2B) <<< 9
81+
c.k[2*i+1] = rol(2*B+A, 9)
82+
}
83+
84+
// Calculate sboxes
85+
switch k {
86+
case 2:
87+
for i := 0; i <= 255; i++ {
88+
c.s[0][i] = mdsColumnMult(sbox[1][sbox[0][sbox[0][byte(i)]^S[0]]^S[4]], 0)
89+
c.s[1][i] = mdsColumnMult(sbox[0][sbox[0][sbox[1][byte(i)]^S[1]]^S[5]], 1)
90+
c.s[2][i] = mdsColumnMult(sbox[1][sbox[1][sbox[0][byte(i)]^S[2]]^S[6]], 2)
91+
c.s[3][i] = mdsColumnMult(sbox[0][sbox[1][sbox[1][byte(i)]^S[3]]^S[7]], 3)
92+
}
93+
case 3:
94+
for i := 0; i < 256; i++ {
95+
c.s[0][i] = mdsColumnMult(sbox[1][sbox[0][sbox[0][sbox[1][byte(i)]^S[0]]^S[4]]^S[8]], 0)
96+
c.s[1][i] = mdsColumnMult(sbox[0][sbox[0][sbox[1][sbox[1][byte(i)]^S[1]]^S[5]]^S[9]], 1)
97+
c.s[2][i] = mdsColumnMult(sbox[1][sbox[1][sbox[0][sbox[0][byte(i)]^S[2]]^S[6]]^S[10]], 2)
98+
c.s[3][i] = mdsColumnMult(sbox[0][sbox[1][sbox[1][sbox[0][byte(i)]^S[3]]^S[7]]^S[11]], 3)
99+
}
100+
default:
101+
for i := 0; i < 256; i++ {
102+
c.s[0][i] = mdsColumnMult(sbox[1][sbox[0][sbox[0][sbox[1][sbox[1][byte(i)]^S[0]]^S[4]]^S[8]]^S[12]], 0)
103+
c.s[1][i] = mdsColumnMult(sbox[0][sbox[0][sbox[1][sbox[1][sbox[0][byte(i)]^S[1]]^S[5]]^S[9]]^S[13]], 1)
104+
c.s[2][i] = mdsColumnMult(sbox[1][sbox[1][sbox[0][sbox[0][sbox[0][byte(i)]^S[2]]^S[6]]^S[10]]^S[14]], 2)
105+
c.s[3][i] = mdsColumnMult(sbox[0][sbox[1][sbox[1][sbox[0][sbox[1][byte(i)]^S[3]]^S[7]]^S[11]]^S[15]], 3)
106+
}
107+
}
108+
109+
return c, nil
110+
}
111+
112+
// Reset zeros the key data, so that it will no longer appear in the process's
113+
// memory.
114+
func (c *Cipher) Reset() {
115+
for i := 0; i < 40; i++ {
116+
c.k[i] = 0
117+
}
118+
for i := 0; i < 4; i++ {
119+
for j := 0; j < 265; j++ {
120+
c.s[i][j] = 0
121+
}
122+
}
123+
}
124+
125+
// BlockSize returns the Twofish block size, 16 bytes.
126+
func (c *Cipher) BlockSize() int { return BlockSize }
127+
128+
// store32l stores src in dst in little-endian form.
129+
func store32l(dst []byte, src uint32) {
130+
dst[0] = byte(src)
131+
dst[1] = byte(src >> 8)
132+
dst[2] = byte(src >> 16)
133+
dst[3] = byte(src >> 24)
134+
return
135+
}
136+
137+
// load32l reads a little-endian uint32 from src.
138+
func load32l(src []byte) uint32 {
139+
return uint32(src[0]) | uint32(src[1])<<8 | uint32(src[2])<<16 | uint32(src[3])<<24
140+
}
141+
142+
// rol returns x after a left circular rotation of y bits.
143+
func rol(x, y uint32) uint32 {
144+
return (x << (y & 31)) | (x >> (32 - (y & 31)))
145+
}
146+
147+
// ror returns x after a right circular rotation of y bits.
148+
func ror(x, y uint32) uint32 {
149+
return (x >> (y & 31)) | (x << (32 - (y & 31)))
150+
}
151+
152+
// The RS matrix. See [TWOFISH] 4.3
153+
var rs = [4][8]byte{
154+
{0x01, 0xA4, 0x55, 0x87, 0x5A, 0x58, 0xDB, 0x9E},
155+
{0xA4, 0x56, 0x82, 0xF3, 0x1E, 0xC6, 0x68, 0xE5},
156+
{0x02, 0xA1, 0xFC, 0xC1, 0x47, 0xAE, 0x3D, 0x19},
157+
{0xA4, 0x55, 0x87, 0x5A, 0x58, 0xDB, 0x9E, 0x03},
158+
}
159+
160+
// sbox tables
161+
var sbox = [2][256]byte{
162+
{
163+
0xa9, 0x67, 0xb3, 0xe8, 0x04, 0xfd, 0xa3, 0x76, 0x9a, 0x92, 0x80, 0x78, 0xe4, 0xdd, 0xd1, 0x38,
164+
0x0d, 0xc6, 0x35, 0x98, 0x18, 0xf7, 0xec, 0x6c, 0x43, 0x75, 0x37, 0x26, 0xfa, 0x13, 0x94, 0x48,
165+
0xf2, 0xd0, 0x8b, 0x30, 0x84, 0x54, 0xdf, 0x23, 0x19, 0x5b, 0x3d, 0x59, 0xf3, 0xae, 0xa2, 0x82,
166+
0x63, 0x01, 0x83, 0x2e, 0xd9, 0x51, 0x9b, 0x7c, 0xa6, 0xeb, 0xa5, 0xbe, 0x16, 0x0c, 0xe3, 0x61,
167+
0xc0, 0x8c, 0x3a, 0xf5, 0x73, 0x2c, 0x25, 0x0b, 0xbb, 0x4e, 0x89, 0x6b, 0x53, 0x6a, 0xb4, 0xf1,
168+
0xe1, 0xe6, 0xbd, 0x45, 0xe2, 0xf4, 0xb6, 0x66, 0xcc, 0x95, 0x03, 0x56, 0xd4, 0x1c, 0x1e, 0xd7,
169+
0xfb, 0xc3, 0x8e, 0xb5, 0xe9, 0xcf, 0xbf, 0xba, 0xea, 0x77, 0x39, 0xaf, 0x33, 0xc9, 0x62, 0x71,
170+
0x81, 0x79, 0x09, 0xad, 0x24, 0xcd, 0xf9, 0xd8, 0xe5, 0xc5, 0xb9, 0x4d, 0x44, 0x08, 0x86, 0xe7,
171+
0xa1, 0x1d, 0xaa, 0xed, 0x06, 0x70, 0xb2, 0xd2, 0x41, 0x7b, 0xa0, 0x11, 0x31, 0xc2, 0x27, 0x90,
172+
0x20, 0xf6, 0x60, 0xff, 0x96, 0x5c, 0xb1, 0xab, 0x9e, 0x9c, 0x52, 0x1b, 0x5f, 0x93, 0x0a, 0xef,
173+
0x91, 0x85, 0x49, 0xee, 0x2d, 0x4f, 0x8f, 0x3b, 0x47, 0x87, 0x6d, 0x46, 0xd6, 0x3e, 0x69, 0x64,
174+
0x2a, 0xce, 0xcb, 0x2f, 0xfc, 0x97, 0x05, 0x7a, 0xac, 0x7f, 0xd5, 0x1a, 0x4b, 0x0e, 0xa7, 0x5a,
175+
0x28, 0x14, 0x3f, 0x29, 0x88, 0x3c, 0x4c, 0x02, 0xb8, 0xda, 0xb0, 0x17, 0x55, 0x1f, 0x8a, 0x7d,
176+
0x57, 0xc7, 0x8d, 0x74, 0xb7, 0xc4, 0x9f, 0x72, 0x7e, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34,
177+
0x6e, 0x50, 0xde, 0x68, 0x65, 0xbc, 0xdb, 0xf8, 0xc8, 0xa8, 0x2b, 0x40, 0xdc, 0xfe, 0x32, 0xa4,
178+
0xca, 0x10, 0x21, 0xf0, 0xd3, 0x5d, 0x0f, 0x00, 0x6f, 0x9d, 0x36, 0x42, 0x4a, 0x5e, 0xc1, 0xe0,
179+
},
180+
{
181+
0x75, 0xf3, 0xc6, 0xf4, 0xdb, 0x7b, 0xfb, 0xc8, 0x4a, 0xd3, 0xe6, 0x6b, 0x45, 0x7d, 0xe8, 0x4b,
182+
0xd6, 0x32, 0xd8, 0xfd, 0x37, 0x71, 0xf1, 0xe1, 0x30, 0x0f, 0xf8, 0x1b, 0x87, 0xfa, 0x06, 0x3f,
183+
0x5e, 0xba, 0xae, 0x5b, 0x8a, 0x00, 0xbc, 0x9d, 0x6d, 0xc1, 0xb1, 0x0e, 0x80, 0x5d, 0xd2, 0xd5,
184+
0xa0, 0x84, 0x07, 0x14, 0xb5, 0x90, 0x2c, 0xa3, 0xb2, 0x73, 0x4c, 0x54, 0x92, 0x74, 0x36, 0x51,
185+
0x38, 0xb0, 0xbd, 0x5a, 0xfc, 0x60, 0x62, 0x96, 0x6c, 0x42, 0xf7, 0x10, 0x7c, 0x28, 0x27, 0x8c,
186+
0x13, 0x95, 0x9c, 0xc7, 0x24, 0x46, 0x3b, 0x70, 0xca, 0xe3, 0x85, 0xcb, 0x11, 0xd0, 0x93, 0xb8,
187+
0xa6, 0x83, 0x20, 0xff, 0x9f, 0x77, 0xc3, 0xcc, 0x03, 0x6f, 0x08, 0xbf, 0x40, 0xe7, 0x2b, 0xe2,
188+
0x79, 0x0c, 0xaa, 0x82, 0x41, 0x3a, 0xea, 0xb9, 0xe4, 0x9a, 0xa4, 0x97, 0x7e, 0xda, 0x7a, 0x17,
189+
0x66, 0x94, 0xa1, 0x1d, 0x3d, 0xf0, 0xde, 0xb3, 0x0b, 0x72, 0xa7, 0x1c, 0xef, 0xd1, 0x53, 0x3e,
190+
0x8f, 0x33, 0x26, 0x5f, 0xec, 0x76, 0x2a, 0x49, 0x81, 0x88, 0xee, 0x21, 0xc4, 0x1a, 0xeb, 0xd9,
191+
0xc5, 0x39, 0x99, 0xcd, 0xad, 0x31, 0x8b, 0x01, 0x18, 0x23, 0xdd, 0x1f, 0x4e, 0x2d, 0xf9, 0x48,
192+
0x4f, 0xf2, 0x65, 0x8e, 0x78, 0x5c, 0x58, 0x19, 0x8d, 0xe5, 0x98, 0x57, 0x67, 0x7f, 0x05, 0x64,
193+
0xaf, 0x63, 0xb6, 0xfe, 0xf5, 0xb7, 0x3c, 0xa5, 0xce, 0xe9, 0x68, 0x44, 0xe0, 0x4d, 0x43, 0x69,
194+
0x29, 0x2e, 0xac, 0x15, 0x59, 0xa8, 0x0a, 0x9e, 0x6e, 0x47, 0xdf, 0x34, 0x35, 0x6a, 0xcf, 0xdc,
195+
0x22, 0xc9, 0xc0, 0x9b, 0x89, 0xd4, 0xed, 0xab, 0x12, 0xa2, 0x0d, 0x52, 0xbb, 0x02, 0x2f, 0xa9,
196+
0xd7, 0x61, 0x1e, 0xb4, 0x50, 0x04, 0xf6, 0xc2, 0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xbe, 0x91,
197+
},
198+
}
199+
200+
// gfMult returns a·b in GF(2^8)/p
201+
func gfMult(a, b byte, p uint32) byte {
202+
B := [2]uint32{0, uint32(b)}
203+
P := [2]uint32{0, p}
204+
var result uint32
205+
206+
// branchless GF multiplier
207+
for i := 0; i < 7; i++ {
208+
result ^= B[a&1]
209+
a >>= 1
210+
B[1] = P[B[1]>>7] ^ (B[1] << 1)
211+
}
212+
result ^= B[a&1]
213+
return byte(result)
214+
}
215+
216+
// mdsColumnMult calculates y{col} where [y0 y1 y2 y3] = MDS . [x0]
217+
func mdsColumnMult(in byte, col int) uint32 {
218+
mul01 := in
219+
mul5B := gfMult(in, 0x5B, mdsPolynomial)
220+
mulEF := gfMult(in, 0xEF, mdsPolynomial)
221+
222+
switch col {
223+
case 0:
224+
return uint32(mul01) | uint32(mul5B)<<8 | uint32(mulEF)<<16 | uint32(mulEF)<<24
225+
case 1:
226+
return uint32(mulEF) | uint32(mulEF)<<8 | uint32(mul5B)<<16 | uint32(mul01)<<24
227+
case 2:
228+
return uint32(mul5B) | uint32(mulEF)<<8 | uint32(mul01)<<16 | uint32(mulEF)<<24
229+
case 3:
230+
return uint32(mul5B) | uint32(mul01)<<8 | uint32(mulEF)<<16 | uint32(mul5B)<<24
231+
}
232+
233+
panic("unreachable")
234+
}
235+
236+
// h implements the S-box generation function. See [TWOFISH] 4.3.5
237+
func h(in, key []byte, offset int) uint32 {
238+
var y [4]byte
239+
for x := 0; x < 4; x++ {
240+
y[x] = in[x]
241+
}
242+
switch len(key) / 8 {
243+
case 4:
244+
y[0] = sbox[1][y[0]] ^ key[4*(6+offset)+0]
245+
y[1] = sbox[0][y[1]] ^ key[4*(6+offset)+1]
246+
y[2] = sbox[0][y[2]] ^ key[4*(6+offset)+2]
247+
y[3] = sbox[1][y[3]] ^ key[4*(6+offset)+3]
248+
fallthrough
249+
case 3:
250+
y[0] = sbox[1][y[0]] ^ key[4*(4+offset)+0]
251+
y[1] = sbox[1][y[1]] ^ key[4*(4+offset)+1]
252+
y[2] = sbox[0][y[2]] ^ key[4*(4+offset)+2]
253+
y[3] = sbox[0][y[3]] ^ key[4*(4+offset)+3]
254+
fallthrough
255+
case 2:
256+
y[0] = sbox[1][sbox[0][sbox[0][y[0]]^key[4*(2+offset)+0]]^key[4*(0+offset)+0]]
257+
y[1] = sbox[0][sbox[0][sbox[1][y[1]]^key[4*(2+offset)+1]]^key[4*(0+offset)+1]]
258+
y[2] = sbox[1][sbox[1][sbox[0][y[2]]^key[4*(2+offset)+2]]^key[4*(0+offset)+2]]
259+
y[3] = sbox[0][sbox[1][sbox[1][y[3]]^key[4*(2+offset)+3]]^key[4*(0+offset)+3]]
260+
}
261+
// [y0 y1 y2 y3] = MDS . [x0 x1 x2 x3]
262+
var mdsMult uint32
263+
for i := 0; i < 4; i++ {
264+
mdsMult ^= mdsColumnMult(y[i], i)
265+
}
266+
return mdsMult
267+
}
268+
269+
// Encrypt encrypts a 16-byte block from src to dst, which may overlap.
270+
// Note that for amounts of data larger than a block,
271+
// it is not safe to just call Encrypt on successive blocks;
272+
// instead, use an encryption mode like CBC (see crypto/block/cbc.go).
273+
func (skey *Cipher) Encrypt(dst, src []byte) {
274+
S1 := skey.s[0]
275+
S2 := skey.s[1]
276+
S3 := skey.s[2]
277+
S4 := skey.s[3]
278+
279+
// Load input
280+
a := load32l(src[0:4])
281+
b := load32l(src[4:8])
282+
c := load32l(src[8:12])
283+
d := load32l(src[12:16])
284+
285+
// Pre-whitening
286+
a ^= skey.k[0]
287+
b ^= skey.k[1]
288+
c ^= skey.k[2]
289+
d ^= skey.k[3]
290+
291+
for i := 0; i < 8; i++ {
292+
k := skey.k[8+i*4 : 12+i*4]
293+
t2 := S2[byte(b)] ^ S3[byte(b>>8)] ^ S4[byte(b>>16)] ^ S1[byte(b>>24)]
294+
t1 := S1[byte(a)] ^ S2[byte(a>>8)] ^ S3[byte(a>>16)] ^ S4[byte(a>>24)] + t2
295+
c = ror(c^(t1+k[0]), 1)
296+
d = rol(d, 1) ^ (t2 + t1 + k[1])
297+
298+
t2 = S2[byte(d)] ^ S3[byte(d>>8)] ^ S4[byte(d>>16)] ^ S1[byte(d>>24)]
299+
t1 = S1[byte(c)] ^ S2[byte(c>>8)] ^ S3[byte(c>>16)] ^ S4[byte(c>>24)] + t2
300+
a = ror(a^(t1+k[2]), 1)
301+
b = rol(b, 1) ^ (t2 + t1 + k[3])
302+
}
303+
304+
// Output with "undo last swap"
305+
ta := c ^ skey.k[4]
306+
tb := d ^ skey.k[5]
307+
tc := a ^ skey.k[6]
308+
td := b ^ skey.k[7]
309+
310+
store32l(dst[0:4], ta)
311+
store32l(dst[4:8], tb)
312+
store32l(dst[8:12], tc)
313+
store32l(dst[12:16], td)
314+
}
315+
316+
// Decrypt decrypts a 16-byte block from src to dst, which may overlap.
317+
func (skey *Cipher) Decrypt(dst, src []byte) {
318+
S1 := skey.s[0]
319+
S2 := skey.s[1]
320+
S3 := skey.s[2]
321+
S4 := skey.s[3]
322+
323+
// Load input
324+
ta := load32l(src[0:4])
325+
tb := load32l(src[4:8])
326+
tc := load32l(src[8:12])
327+
td := load32l(src[12:16])
328+
329+
// Undo undo final swap
330+
a := tc ^ skey.k[6]
331+
b := td ^ skey.k[7]
332+
c := ta ^ skey.k[4]
333+
d := tb ^ skey.k[5]
334+
335+
for i := 8; i > 0; i-- {
336+
k := skey.k[4+i*4 : 8+i*4]
337+
t2 := S2[byte(d)] ^ S3[byte(d>>8)] ^ S4[byte(d>>16)] ^ S1[byte(d>>24)]
338+
t1 := S1[byte(c)] ^ S2[byte(c>>8)] ^ S3[byte(c>>16)] ^ S4[byte(c>>24)] + t2
339+
a = rol(a, 1) ^ (t1 + k[2])
340+
b = ror(b^(t2+t1+k[3]), 1)
341+
342+
t2 = S2[byte(b)] ^ S3[byte(b>>8)] ^ S4[byte(b>>16)] ^ S1[byte(b>>24)]
343+
t1 = S1[byte(a)] ^ S2[byte(a>>8)] ^ S3[byte(a>>16)] ^ S4[byte(a>>24)] + t2
344+
c = rol(c, 1) ^ (t1 + k[0])
345+
d = ror(d^(t2+t1+k[1]), 1)
346+
}
347+
348+
// Undo pre-whitening
349+
a ^= skey.k[0]
350+
b ^= skey.k[1]
351+
c ^= skey.k[2]
352+
d ^= skey.k[3]
353+
354+
store32l(dst[0:4], a)
355+
store32l(dst[4:8], b)
356+
store32l(dst[8:12], c)
357+
store32l(dst[12:16], d)
358+
}

0 commit comments

Comments
 (0)