github.com/Asutorufa/yuhaiin@v0.3.6-0.20240502055049-7984da7023a0/pkg/net/proxy/shadowsocksr/cipher/idea/idea.go (about) 1 // Package idea implements the IDEA block cipher 2 /* 3 For more information, please see https://en.wikipedia.org/wiki/International_Data_Encryption_Algorithm 4 This implementation derived from Public Domain code by Colin Plumb available at https://www.schneier.com/book-applied-source.html 5 */ 6 package idea 7 8 import ( 9 "crypto/cipher" 10 "encoding/binary" 11 "strconv" 12 ) 13 14 const rounds = 8 15 const keyLen = (6*rounds + 4) 16 17 // KeySizeError is returned for incorrect key sizes 18 type KeySizeError int 19 20 func (k KeySizeError) Error() string { 21 return "idea: invalid key size " + strconv.Itoa(int(k)) 22 } 23 24 type ideaCipher struct { 25 ek [keyLen]uint16 26 dk [keyLen]uint16 27 } 28 29 // from github.com/dgryski/go-idea 30 // NewCipher returns a cipher.Block implementing the IDEA block cipher. The key argument should be 16 bytes. 31 func NewCipher(key []byte) (cipher.Block, error) { 32 33 if l := len(key); l != 16 { 34 return nil, KeySizeError(l) 35 } 36 37 cipher := &ideaCipher{} 38 39 expandKey(key, cipher.ek[:]) 40 41 // key inversion is expensive, we could do this lazily 42 invertKey(cipher.ek[:], cipher.dk[:]) 43 44 return cipher, nil 45 } 46 47 func (c *ideaCipher) BlockSize() int { return 8 } 48 func (c *ideaCipher) Encrypt(dst, src []byte) { crypt(src, dst, c.ek[:]) } 49 func (c *ideaCipher) Decrypt(dst, src []byte) { crypt(src, dst, c.dk[:]) } 50 51 // mulInv computes the multiplicative inverse of x mod 2^16+1 52 func mulInv(x uint16) (ret uint16) { 53 54 if x <= 1 { 55 return x // 0 and 1 are self-inverse 56 } 57 58 t1 := uint16(0x10001 / uint32(x)) // Since x >= 2, this fits into 16 bits 59 y := uint16(0x10001 % uint32(x)) 60 61 if y == 1 { 62 return 1 - t1 63 } 64 65 var t0 uint16 = 1 66 var q uint16 67 68 for y != 1 { 69 q = x / y 70 x = x % y 71 t0 += q * t1 72 if x == 1 { 73 return t0 74 } 75 q = y / x 76 y = y % x 77 t1 += q * t0 78 } 79 return 1 - t1 80 } 81 82 // mul computes x*y mod 2^16+1 83 func mul(x, y uint16) uint16 { 84 85 if y == 0 { 86 return 1 - x 87 } 88 89 if x == 0 { 90 return 1 - y 91 } 92 93 t32 := uint32(x) * uint32(y) 94 x = uint16(t32) 95 y = uint16(t32 >> 16) 96 97 if x < y { 98 return x - y + 1 99 } 100 101 return x - y 102 } 103 104 // expandKey computes encryption round-keys from a user-supplied key 105 func expandKey(key []byte, EK []uint16) { 106 var i, j int 107 108 for j = 0; j < 8; j++ { 109 EK[j] = (uint16(key[0]) << 8) + uint16(key[1]) 110 key = key[2:] 111 } 112 for i = 0; j < keyLen; j++ { 113 i++ 114 EK[i+7] = EK[i&7]<<9 | EK[(i+1)&7]>>7 115 EK = EK[i&8:] 116 i &= 7 117 } 118 } 119 120 // invertKey computes the decryption round-keys from a set of encryption round-keys 121 func invertKey(EK []uint16, DK []uint16) { 122 123 var t1, t2, t3 uint16 124 var p [keyLen]uint16 125 pidx := keyLen 126 ekidx := 0 127 128 t1 = mulInv(EK[ekidx]) 129 ekidx++ 130 t2 = -EK[ekidx] 131 ekidx++ 132 t3 = -EK[ekidx] 133 ekidx++ 134 pidx-- 135 p[pidx] = mulInv(EK[ekidx]) 136 ekidx++ 137 pidx-- 138 p[pidx] = t3 139 pidx-- 140 p[pidx] = t2 141 pidx-- 142 p[pidx] = t1 143 144 for i := 0; i < rounds-1; i++ { 145 t1 = EK[ekidx] 146 ekidx++ 147 pidx-- 148 p[pidx] = EK[ekidx] 149 ekidx++ 150 pidx-- 151 p[pidx] = t1 152 153 t1 = mulInv(EK[ekidx]) 154 ekidx++ 155 t2 = -EK[ekidx] 156 ekidx++ 157 t3 = -EK[ekidx] 158 ekidx++ 159 pidx-- 160 p[pidx] = mulInv(EK[ekidx]) 161 ekidx++ 162 pidx-- 163 p[pidx] = t2 164 pidx-- 165 p[pidx] = t3 166 pidx-- 167 p[pidx] = t1 168 } 169 170 t1 = EK[ekidx] 171 ekidx++ 172 pidx-- 173 p[pidx] = EK[ekidx] 174 ekidx++ 175 pidx-- 176 p[pidx] = t1 177 178 t1 = mulInv(EK[ekidx]) 179 ekidx++ 180 t2 = -EK[ekidx] 181 ekidx++ 182 t3 = -EK[ekidx] 183 ekidx++ 184 pidx-- 185 p[pidx] = mulInv(EK[ekidx]) 186 pidx-- 187 p[pidx] = t3 188 pidx-- 189 p[pidx] = t2 190 pidx-- 191 p[pidx] = t1 192 193 copy(DK, p[:]) 194 } 195 196 // crypt performs IDEA encryption given input/output buffers and a set of round-keys 197 func crypt(inbuf, outbuf []byte, key []uint16) { 198 199 var x1, x2, x3, x4, s2, s3 uint16 200 201 x1 = binary.BigEndian.Uint16(inbuf[0:]) 202 x2 = binary.BigEndian.Uint16(inbuf[2:]) 203 x3 = binary.BigEndian.Uint16(inbuf[4:]) 204 x4 = binary.BigEndian.Uint16(inbuf[6:]) 205 206 for r := rounds; r > 0; r-- { 207 208 x1 = mul(x1, key[0]) 209 key = key[1:] 210 x2 += key[0] 211 key = key[1:] 212 x3 += key[0] 213 key = key[1:] 214 215 x4 = mul(x4, key[0]) 216 key = key[1:] 217 218 s3 = x3 219 x3 ^= x1 220 x3 = mul(x3, key[0]) 221 key = key[1:] 222 s2 = x2 223 224 x2 ^= x4 225 x2 += x3 226 x2 = mul(x2, key[0]) 227 key = key[1:] 228 x3 += x2 229 230 x1 ^= x2 231 x4 ^= x3 232 233 x2 ^= s3 234 x3 ^= s2 235 236 } 237 x1 = mul(x1, key[0]) 238 key = key[1:] 239 240 x3 += key[0] 241 key = key[1:] 242 x2 += key[0] 243 key = key[1:] 244 x4 = mul(x4, key[0]) 245 246 binary.BigEndian.PutUint16(outbuf[0:], x1) 247 binary.BigEndian.PutUint16(outbuf[2:], x3) 248 binary.BigEndian.PutUint16(outbuf[4:], x2) 249 binary.BigEndian.PutUint16(outbuf[6:], x4) 250 }