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  }