|
| 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