-
Notifications
You must be signed in to change notification settings - Fork 2
/
skip32.go
145 lines (107 loc) · 4.25 KB
/
skip32.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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Copyright (c) 2012 Damian Gryski <[email protected]>
// Licensed under MIT
// Package skip32 implements the Skip32 blockcipher
/*
SKIP32 is a 32-bit block cipher based on SKIPJACK, written by Greg Rose of QUALCOMM Australia.
It is useful for obfuscating small integers (like sequential database ids)
that are exposed to prevent an analysis of growth rates as in:
https://en.wikipedia.org/wiki/German_tank_problem
This library deliberately exposes only the integer obfuscation routines and
hides the low-level encryption.
Using this routine to hide IDs is not sufficient security by itself. Please
ensure your application does secondary validation and do not rely on the
secrecy of the generated IDs.
*/
package skip32
import (
"errors"
"strconv"
)
var ftable = [...]byte{
0xa3, 0xd7, 0x09, 0x83, 0xf8, 0x48, 0xf6, 0xf4, 0xb3, 0x21, 0x15, 0x78, 0x99, 0xb1, 0xaf, 0xf9,
0xe7, 0x2d, 0x4d, 0x8a, 0xce, 0x4c, 0xca, 0x2e, 0x52, 0x95, 0xd9, 0x1e, 0x4e, 0x38, 0x44, 0x28,
0x0a, 0xdf, 0x02, 0xa0, 0x17, 0xf1, 0x60, 0x68, 0x12, 0xb7, 0x7a, 0xc3, 0xe9, 0xfa, 0x3d, 0x53,
0x96, 0x84, 0x6b, 0xba, 0xf2, 0x63, 0x9a, 0x19, 0x7c, 0xae, 0xe5, 0xf5, 0xf7, 0x16, 0x6a, 0xa2,
0x39, 0xb6, 0x7b, 0x0f, 0xc1, 0x93, 0x81, 0x1b, 0xee, 0xb4, 0x1a, 0xea, 0xd0, 0x91, 0x2f, 0xb8,
0x55, 0xb9, 0xda, 0x85, 0x3f, 0x41, 0xbf, 0xe0, 0x5a, 0x58, 0x80, 0x5f, 0x66, 0x0b, 0xd8, 0x90,
0x35, 0xd5, 0xc0, 0xa7, 0x33, 0x06, 0x65, 0x69, 0x45, 0x00, 0x94, 0x56, 0x6d, 0x98, 0x9b, 0x76,
0x97, 0xfc, 0xb2, 0xc2, 0xb0, 0xfe, 0xdb, 0x20, 0xe1, 0xeb, 0xd6, 0xe4, 0xdd, 0x47, 0x4a, 0x1d,
0x42, 0xed, 0x9e, 0x6e, 0x49, 0x3c, 0xcd, 0x43, 0x27, 0xd2, 0x07, 0xd4, 0xde, 0xc7, 0x67, 0x18,
0x89, 0xcb, 0x30, 0x1f, 0x8d, 0xc6, 0x8f, 0xaa, 0xc8, 0x74, 0xdc, 0xc9, 0x5d, 0x5c, 0x31, 0xa4,
0x70, 0x88, 0x61, 0x2c, 0x9f, 0x0d, 0x2b, 0x87, 0x50, 0x82, 0x54, 0x64, 0x26, 0x7d, 0x03, 0x40,
0x34, 0x4b, 0x1c, 0x73, 0xd1, 0xc4, 0xfd, 0x3b, 0xcc, 0xfb, 0x7f, 0xab, 0xe6, 0x3e, 0x5b, 0xa5,
0xad, 0x04, 0x23, 0x9c, 0x14, 0x51, 0x22, 0xf0, 0x29, 0x79, 0x71, 0x7e, 0xff, 0x8c, 0x0e, 0xe2,
0x0c, 0xef, 0xbc, 0x72, 0x75, 0x6f, 0x37, 0xa1, 0xec, 0xd3, 0x8e, 0x62, 0x8b, 0x86, 0x10, 0xe8,
0x08, 0x77, 0x11, 0xbe, 0x92, 0x4f, 0x24, 0xc5, 0x32, 0x36, 0x9d, 0xcf, 0xf3, 0xa6, 0xbb, 0xac,
0x5e, 0x6c, 0xa9, 0x13, 0x57, 0x25, 0xb5, 0xe3, 0xbd, 0xa8, 0x3a, 0x01, 0x05, 0x59, 0x2a, 0x46,
}
func g(key []byte, k int, w uint16) uint16 {
g1 := byte((w >> 8) & 0xff)
g2 := byte(w & 0xff)
g3 := ftable[g2^key[(4*k+0)%10]] ^ g1
g4 := ftable[g3^key[(4*k+1)%10]] ^ g2
g5 := ftable[g4^key[(4*k+2)%10]] ^ g3
g6 := ftable[g5^key[(4*k+3)%10]] ^ g4
return (uint16(g5) << 8) + uint16(g6)
}
func crypt32(key []byte, buf []byte, encrypt bool) {
var kstep, k int
if encrypt {
kstep = 1
k = 0
} else {
kstep = -1
k = 23
}
/* pack into words */
wl := (uint16(buf[0]) << 8) + uint16(buf[1])
wr := (uint16(buf[2]) << 8) + uint16(buf[3])
/* 24 feistel rounds, doubled up */
for i := 0; i < 24/2; i++ {
wr ^= g(key, k, wl) ^ uint16(k)
k += kstep
wl ^= g(key, k, wr) ^ uint16(k)
k += kstep
}
/* implicitly swap halves while unpacking */
buf[0] = byte(wr >> 8)
buf[1] = byte(wr & 0xFF)
buf[2] = byte(wl >> 8)
buf[3] = byte(wl & 0xFF)
}
// Skip32 is a 32-bit integer obfuscator
type Skip32 struct {
key []byte
}
// New returns a new Skip32 obfuscator. key must be 10 bytes (80 bits).
func New(key []byte) (*Skip32, error) {
if l := len(key); l != 10 {
return nil, errors.New("Invalid key size: " + strconv.Itoa(l))
}
s := new(Skip32)
s.key = make([]byte, 10)
copy(s.key, key)
return s, nil
}
// Obfus obfuscates a uint32
func (s *Skip32) Obfus(id uint32) uint32 {
var buf [4]byte
buf[0] = byte((id >> 24) & 0xff)
buf[1] = byte((id >> 16) & 0xff)
buf[2] = byte((id >> 8) & 0xff)
buf[3] = byte((id >> 0) & 0xff)
crypt32(s.key, buf[:], true /* encrypt */)
j := (uint32(buf[0]) << 24) | (uint32(buf[1]) << 16) | (uint32(buf[2]) << 8) | uint32(buf[3])
return j
}
// Unobfus unobfuscates an uint32
func (s *Skip32) Unobfus(id uint32) uint32 {
var buf [4]byte
buf[0] = byte((id >> 24) & 0xff)
buf[1] = byte((id >> 16) & 0xff)
buf[2] = byte((id >> 8) & 0xff)
buf[3] = byte((id >> 0) & 0xff)
crypt32(s.key, buf[:], false /* decrypt */)
j := (uint32(buf[0]) << 24) | (uint32(buf[1]) << 16) | (uint32(buf[2]) << 8) | uint32(buf[3])
return j
}