-
Notifications
You must be signed in to change notification settings - Fork 24
/
cipher64.go
99 lines (90 loc) · 2.76 KB
/
cipher64.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package rc5
import (
"crypto/cipher"
"encoding/binary"
"math/bits"
)
const (
// BlockSize the RC5/64 block size in bytes.
BlockSize64 = 16
P64 = 0xB7E151628AED2A6B
Q64 = 0x9E3779B97F4A7C15
)
type rc5Cipher64 struct {
rounds uint
rk []uint64
}
func newCipher64(key []byte, rounds uint) (cipher.Block, error) {
c := &rc5Cipher64{}
c.rounds = rounds
c.rk = make([]uint64, (rounds+1)<<1)
expandKey64(key, c.rk)
return c, nil
}
func expandKey64(key []byte, rk []uint64) {
roundKeys := len(rk)
// L is initially a c-length list of 0-valued w-length words
L := make([]uint64, len(key)/8)
lenL := len(L)
for i := 0; i < lenL; i++ {
L[i] = binary.LittleEndian.Uint64(key[:8])
key = key[8:]
}
// Initialize key-independent pseudorandom S array
// S is initially a t=2(r+1) length list of undefined w-length words
rk[0] = P64
for i := 1; i < roundKeys; i++ {
rk[i] = rk[i-1] + Q64
}
// The main key scheduling loop
var A uint64
var B uint64
var i, j int
for k := 0; k < 3*roundKeys; k++ {
rk[i] = bits.RotateLeft64(rk[i]+(A+B), 3)
A = rk[i]
L[j] = bits.RotateLeft64(L[j]+(A+B), int(A+B))
B = L[j]
i = (i + 1) % roundKeys
j = (j + 1) % lenL
}
}
func (c *rc5Cipher64) BlockSize() int { return BlockSize64 }
func (c *rc5Cipher64) Encrypt(dst, src []byte) {
if len(src) < BlockSize64 {
panic("rc5-64: input not full block")
}
if len(dst) < BlockSize64 {
panic("rc5-64: output not full block")
}
if inexactOverlap(dst[:BlockSize64], src[:BlockSize64]) {
panic("rc5-64: invalid buffer overlap")
}
A := binary.LittleEndian.Uint64(src[:8]) + c.rk[0]
B := binary.LittleEndian.Uint64(src[8:BlockSize64]) + c.rk[1]
for r := 1; r <= int(c.rounds); r++ {
A = bits.RotateLeft64(A^B, int(B)) + c.rk[r<<1]
B = bits.RotateLeft64(B^A, int(A)) + c.rk[r<<1+1]
}
binary.LittleEndian.PutUint64(dst[:8], A)
binary.LittleEndian.PutUint64(dst[8:16], B)
}
func (c *rc5Cipher64) Decrypt(dst, src []byte) {
if len(src) < BlockSize64 {
panic("rc5-64: input not full block")
}
if len(dst) < BlockSize64 {
panic("rc5-64: output not full block")
}
if inexactOverlap(dst[:BlockSize64], src[:BlockSize64]) {
panic("rc5-64: invalid buffer overlap")
}
A := binary.LittleEndian.Uint64(src[:8])
B := binary.LittleEndian.Uint64(src[8:16])
for r := c.rounds; r >= 1; r-- {
B = A ^ bits.RotateLeft64(B-c.rk[r<<1+1], -int(A))
A = B ^ bits.RotateLeft64(A-c.rk[r<<1], -int(B))
}
binary.LittleEndian.PutUint64(dst[:8], A-c.rk[0])
binary.LittleEndian.PutUint64(dst[8:16], B-c.rk[1])
}