Golang仿台服DOF DNF数据库的加密与解密
什么是TEA加密
TEA算法是由剑桥大学计算机实验室的David Wheeler和Roger Needham于1994年发明,TEA是Tiny Encryption Algorithm的缩写,以加密解密速度快,实现简单著称。TEA算法每一次可以操作64bit(8byte),采用128bit(16byte)作为key,算法采用迭代的形式,推荐的迭代轮数是64轮,最少32轮。为解决TEA算法密钥表攻击的问题,TEA算法先后经历了几次改进,从XTEA到BLOCK TEA,直至最新的XXTEA。XTEA也称做TEAN,它使用与TEA相同的简单运算,但四个子密钥采取不正规的方式进行混合以阻止密钥表攻击。Block TEA算法可以对32位的任意整数倍长度的变量块进行加解密的操作,该算法将XTEA轮循函数依次应用于块中的每个字,并且将它附加于被应用字的邻字。XXTEA使用跟Block TEA相似的结构,但在处理块中每个字时利用了相邻字,且用拥有两个输入量的MX函数代替了XTEA轮循函数。上面提到的相邻字其实就是数组中相邻的项。
TEA系列算法中均使用了一个DELTA常数,但DELTA的值对算法并无什么影响,只是为了避免不良的取值,推荐DELTA的值取为黄金分割数(5√-2)/2与232的乘积,取整后的十六进制值为0x9e3779B9,用于保证每一轮加密都不相同。
本案例仅实现台服DNF的加解密TEA版本,不完全适用于原本TEA加密,本案例仅用于学习,请不要用于商业。
台服DNF 地下城与勇士的C++版本对数据库加密
#include <cstring>
#include <cstdio>
char *key = "troqkddmtroqkcdm";
char *postfix = "e8b10c1f8bc3595be8b10c1f8bc3595b";
class Encrypt {
public:
void getKeyPre(char sixkey[9], char *ret) {
ret[0] = 0;
char res1[80];
encrypt(sixkey, res1);
strcat(ret, res1);
strcat(ret, postfix);
}
private:
long long bytes_to_long(char *t) {
unsigned char *r = (unsigned char *) t;
long long a = (0xFFFFFFFF & (unsigned int) r[0]) << 24;
long long b = (0xFFFFFFFF & (unsigned int) r[1]) << 16;
long long c = (0xFFFFFFFF & (unsigned int) r[2]) << 8;
long long d = r[3];
return (a + b + c + d);
}
void long_to_bytes(long long v, char *ret) {
int a = (int) ((0xFF000000 & v) >> 24);
int b = (int) ((0xFF0000 & v) >> 16);
int c = (int) ((0xFF00 & v) >> 8);
int d = (int) (0xFF & v);
sprintf(ret, "%02x%02x%02x%02x", a, b, c, d);
}
long long unpack(char *tmp, int start, int len) {
unsigned char *arr = (unsigned char *) (tmp + start);
long long d = arr[0];
long long c = arr[1];
long long b = arr[2];
long long a = arr[3];
a = a << 24;
b = b << 16;
c = c << 8;
return (a + b + c + d);
}
void encrypt(char v[9], char *ret) {
long long v0 = bytes_to_long(v);
long long v1 = bytes_to_long(v + 4);
long long sum = 0;
for (int i = 0; i < 32; ++i) {
long long tv1 = toUInt32(toUInt32(v1 << 4)) ^ toUInt32((v1 >> 5 & 0x07FFFFFF));
long long tv2 = unpack(key, ((int) sum & 3) * 4, 4);
v0 = toUInt32(v0 + (toUInt32(tv1 + v1) ^ toUInt32(tv2 + sum)));
sum = toUInt32(sum + 0x9E3779B9);
tv1 = toUInt32(toUInt32(toUInt32(v0 << 4)) ^ toUInt32((v0 >> 5 & 0x07FFFFFF)));
tv2 = unpack(key, ((int) toUInt32((int) sum >> 11) & 3) * 4, 4);
v1 = toUInt32(v1 + (toUInt32(tv1 + v0) ^ toUInt32(tv2 + sum)));
}
long_to_bytes(v0, ret);
long_to_bytes(v1, ret + 8);
}
long long toUInt32(long long v) {
return (v & 0xFFFFFFFF);
}
}
;
void getKey(char sixkey[9], char *ret) {
Encrypt enc;
enc.getKeyPre(sixkey, ret);
}
int main() {
char password[] = "uu5!^%jg";
char res[100];
getKey(password, res);
printf("%s", res);
return (0);
}
golang版本仿写加、解密
package main
import (
"encoding/binary"
"encoding/hex"
"fmt"
"log"
"strconv"
)
func main() {
var (
yourText = []byte("uu5!^%jg") // 你的加密串(自行修改)
key = []byte("troqkddmtroqkcdm") // 密钥 (勿动)
postFix = "e8b10c1f8bc3595be8b10c1f8bc3595b" // 补充信息(勿动)
)
tc, err := NewCipher(key)
if err != nil {
log.Fatalln(err)
}
dst, dst1 := make([]byte, 8), make([]byte, 8)
tc.Encrypt(dst, yourText)
result := hex.EncodeToString(dst) + postFix
fmt.Println("加密后:", result)
tc.Decrypt(dst1, dst)
fmt.Println("解密后:", string(dst1))
}
type teaCipher struct {
key []byte
}
type KeySizeError int
func (k KeySizeError) Error() string {
return "tea: invalid key size " + strconv.Itoa(int(k))
}
func NewCipher(key []byte) (*teaCipher, error) {
if len(key) != 16 {
return nil, KeySizeError(len(key))
}
cipher := new(teaCipher)
cipher.key = key
return cipher, nil
}
func (c *teaCipher) BlockSize() int {
return 8
}
func (c *teaCipher) Encrypt(dst, src []byte) {
var (
end = binary.BigEndian
v0, v1 = end.Uint32(src), end.Uint32(src[4:])
sum uint32 = 0
delta uint32 = 0x9E3779B9 // 黄金分割位
CorrectionBit uint32 = 0x7FFFFFF // 修正位
)
for i := 0; i < 32; i++ {
tv1 := (v1 << 4) ^ (v1 >> 5 & CorrectionBit)
tv2 := unpack(c.key, (sum&3)*4)
v0 += (tv1 + v1) ^ (tv2 + sum)
sum += delta
tv1 = (v0 << 4) ^ (v0 >> 5 & CorrectionBit)
tv2 = unpack(c.key, ((sum>>11)&3)*4)
v1 += (tv1 + v0) ^ (tv2 + sum)
}
end.PutUint32(dst, v0)
end.PutUint32(dst[4:], v1)
}
func (c *teaCipher) Decrypt(dst, src []byte) {
var (
end = binary.BigEndian
v0, v1 = end.Uint32(src[0:4]), end.Uint32(src[4:8])
delta uint32 = 0x9E3779B9 // 黄金分割位
sum uint32 = delta << 5
CorrectionBit uint32 = 0x7FFFFFF // 修正位
)
for i := 0; i < 32; i++ {
tv1 := (v0 << 4) ^ (v0 >> 5 & CorrectionBit)
tv2 := unpack(c.key, ((sum>>11)&3)*4)
v1 -= (tv1 + v0) ^ (tv2 + sum)
sum -= delta
tv1 = (v1 << 4) ^ (v1 >> 5 & CorrectionBit)
tv2 = unpack(c.key, (sum&3)*4)
v0 -= (tv1 + v1) ^ (tv2 + sum)
}
end.PutUint32(dst, v0)
end.PutUint32(dst[4:], v1)
}
func unpack(tmp []byte, start uint32) uint32 {
tmp = tmp[start:]
a := tmp[3]
b := tmp[2]
c := tmp[1]
d := tmp[0]
return uint32(d) | uint32(c)<<8 | uint32(b)<<16 | uint32(a)<<24
}