KeeLoq加密算法
四个字节的对称加密算法,用于部分通讯协议中,对关键信息加密处理。
目前使用较多的是上位机加密,硬件解密,所以以下C语言有加解密,C#和nodejs的有加密。
最近研究了一种新的文案,通讯登录时校验,可以起到防窃听,防篡改作用,通讯过程中完全不用再加密。
以下为C语言写法
#define KeeLoq_NLF 0x3A5C742E
#define bit(x,n) (((x)>>(n))&1)
#define g5(x,a,b,c,d,e) (bit(x,a)+bit(x,b)*2+bit(x,c)*4+bit(x,d)*8+bit(x,e)*16)
// 加密
u32 KeeLoq_Encrypt (u32 data, u32 key)
{
u32 x = data, r;
for (r = 0; r < 528; r++)
{
x = (x>>1)^((bit(x,0)^bit(x,16)^(u32)bit(key,r&63)^bit(KeeLoq_NLF,g5(x,1,9,20,26,31)))<<31);
}
return x;
}
// 解密
u32 Keeloq_Decrypt(u32 data,u32 key)
{
u32 x = data, r;
for (r = 0; r < 528; r++)
{
x = (x<<1) ^ (bit(x,31)) ^ (bit(x,15)) ^ (bit(key,(15-r)&63)) ^ bit(KeeLoq_NLF,g5(x,0,8,19,25,30));
}
return x;
}
c#
/// <summary>
/// KeeLoq加密算法
/// </summary>
public class KeeLoq
{
/// <summary>
/// 固定公共密钥
/// </summary>
private const UInt64 KeeLoq_NLF = 0x3A5C742E;
/// <summary>
///
/// </summary>
/// <param name="x"></param>
/// <param name="n"></param>
/// <returns></returns>
private static UInt64 bit(UInt64 x, int n)
{
return (x >> n) & 1;
}
/// <summary>
///
/// </summary>
/// <param name="x"></param>
/// <param name="a"></param>
/// <param name="b"></param>
/// <param name="c"></param>
/// <param name="d"></param>
/// <param name="e"></param>
/// <returns></returns>
private static UInt64 g5(UInt64 x, byte a, byte b, byte c, byte d, byte e)
{
return bit(x, a) + bit(x, b) * 2 + bit(x, c) * 4 + bit(x, d) * 8 + bit(x, e) * 16;
}
/// <summary>
/// 加密算法
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <returns></returns>
public static byte[] KeeLoq_Encrypt(byte[] data, byte[] key)
{
Array.Reverse(data);
Array.Reverse(key);
UInt32 userData = BitConverter.ToUInt32(data, 0);
UInt32 uKey = BitConverter.ToUInt32(key, 0);
UInt64 uResult = KeeLoq_Encrypt(userData, uKey);
byte[] resultBytes = BitConverter.GetBytes(uResult);
byte[] outBytes = new byte[4];
Buffer.BlockCopy(resultBytes, 0, outBytes, 0, 4);
Array.Reverse(outBytes);
return outBytes;
}
/// <summary>
///
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <returns></returns>
public static UInt64 KeeLoq_Encrypt(UInt32 data, UInt32 key)
{
UInt64 x = data;
int r;
for (r = 0; r < 528; r++)
{
x = (x >> 1) ^ ((bit(x, 0) ^ bit(x, 16) ^ bit(key, r & 63) ^ bit(KeeLoq_NLF, (int)(g5(x, 1, 9, 20, 26, 31)))) << 31);
}
return x;
}
/ <summary>
/
/ </summary>
/ <param name="data"></param>
/ <param name="key"></param>
/ <returns></returns>
//public UInt64 KeeLoq_Decrypt(UInt32 data, UInt32 key)
//{
// UInt64 x = data;
// int r;
// for (r = 0; r < 528; r++)
// {
// x = (x << 1) ^ bit(x, 31) ^ bit(x, 15) ^ bit(key, (15 - r) & 63) ^ bit(KeeLoq_NLF, (int)g5(x, 0, 8, 19, 25, 30));
// }
// return x;
//}
}
nodejs
/*****************************
* KeeLoq加密算法
*
****************************/
'use strict';
const Long = require("long");
const KeeLoq_NLF = Long.fromBytesBE([0x00, 0x00, 0x00, 0x00, 0x3A, 0x5C, 0x74, 0x2E], false);
function bit(x, n) {
return x.shiftRightUnsigned(n).and(1);
}
function g5(x, a, b, c, d, e) {
//return bit(x, a) + bit(x, b).multiply(2) + bit(x, c).multiply(4) + bit(x, d).multiply(8) + bit(x, e).multiply(16);
return bit(x, a).add(bit(x, b).multiply(2)).add(bit(x, c).multiply(4)).add(bit(x, d).multiply(8)).add(bit(x, e).multiply(16));
}
/**
* 加密
* @param data
* @param key
*/
function encrypt(data, key) {
let x = data;
let r = 0;
for (r = 0; r < 528; r++) {
// x = (x >> 1) ^ ((bit(x, 0) ^ bit(x, 16) ^ bit(key, r & 63) ^ bit(KeeLoq_NLF, (g5(x, 1, 9, 20, 26, 31)))) << 31);
let y = g5(x, 1, 9, 20, 26, 31);
//let h = (x >>> 1);
let h = x.shiftRightUnsigned(1);
if (h < 0) throw new Error(h);
let j = bit(KeeLoq_NLF, y);
if (j < 0) throw new Error(j);
let k = bit(key, r & 63);
if (k < 0) throw new Error(k);
let l = bit(x, 0);
if (l < 0) throw new Error(l);
let m = bit(x, 16);
if (m < 0) throw new Error(m);
//let n = l ^ m ^ k ^ j;
let n = l.xor(m);
if (n < 0) throw new Error(n);
n = n.xor(k);
//if (n < 0) throw new Error(n);
n = n.xor(j);
if (n < 0) throw new Error(n);
//if(n === 1) n = toUint(n);
//let i = n << 31;
//n = Long.fromValue(n);
let i = n.shiftLeft(31);
// if (i === -2147483648) i = 2147483648;
if (i < 0) throw new Error(i);
x = h.xor(i);
x = Long.fromValue(x);
}
return x;
}
exports.encrypt = encrypt;
/**
* 加密
* @param dataBytes
* @param keyBytes
*/
function encryptBytes(dataBytes, keyBytes) {
let data = Long.fromBytesBE([0x00, 0x00, 0x00, 0x00, dataBytes[0], dataBytes[1], dataBytes[2], dataBytes[3]], false);
let key = Long.fromBytesBE([0x00, 0x00, 0x00, 0x00, keyBytes[0], keyBytes[1], keyBytes[2], keyBytes[3]], false);
let result = encrypt(data, key);
let outBytes = Buffer.alloc(4);
let nums = result.toBytesBE();
outBytes[0] = nums[4];
outBytes[1] = nums[5];
outBytes[2] = nums[6];
outBytes[3] = nums[7];
return outBytes;
}
exports.encryptBytes = encryptBytes;