看了看雷登密码,我不确定我是否理解密码:
void raiden(unsigned long *in,unsigned long *res,unsigned long *key)
{
unsigned long b0=in[0],b1=in[1],i,k[4]={key[0],key[1],key[2],key[3]},sk;
for(i=0; i< 16; i++)
{
sk=k[i%4]=((k[0]+k[1])+((k[2]-k[3])ˆ(k[0]<<k[2])));
b0 += ((sk+b1)<<9)ˆ((sk-b1)ˆ((sk+b1)>>14));
b1 += ((sk+b0)<<9)ˆ((sk-b0)ˆ((sk+b0)>>14));
}
res[0]=b0;
res[1]=b1;
}考虑到'key‘(因此'k')是32位值,我预计k2通常会比31大得多,所以上面的代码是未定义的,或者至少定义了编译器实现?
我试图找到更多关于密码的技术文档,它似乎声称它是一个旋转,但在这种情况下,它为什么要使用shift呢?
或者这只是一个半途而废的算法,我甚至不应该去看它?我在考虑用它加密真实的数据
发布于 2014-11-11 00:11:35
不知道为什么你对这个特殊的密码感兴趣,它似乎没有得到太多的发展。从可用的零碎信息来看,似乎通过key3的密钥被视为32位的数量。如果是这样,则未定义表达式(k[0]<<k[2]),如C标准中的以下子句所明确表示的那样:
如果右操作数的值为负值,或大于或等于提升的左操作数的宽度,则行为未定义。
事实上,多年来,我看到了两种不同的移位量行为,它们“大于或等于左操作数的宽度”。
它确实是不可移植的,应该被认为是一个错误。最有可能的是,作者打算行为#2。@chux的评论建议使用uint32_t而不是未签名的long,这也是有意义的。
发布于 2021-02-19 18:59:03
据我所知,Raiden是一个OK算法,没有已知的陷阱,但它没有经过真正的测试,也没有标准化。它的工作原理非常类似于它的其他类别的密码,它应该与他们一样,但很难确定。我在一些非关键应用程序中使用过几次,在这些应用程序中,至少有一些数据真实性保证,但没有对它的实际要求,这是非常好的。
该算法唯一的缺点是,它的推荐实现只在C中提供,它使用按位移位的溢出操作,根据编译器( GCC、IAR、Keil、.的不同版本)、平台上(GCC for x86和ARM给出类似的组装指令,但它们在实际硬件上的执行结果不同)和选择的编程语言(C、Java、D和C++实现可以不同的工作方式),因此不同的设备和程序很有可能对函数的结果有不同的看法。
为了克服这个问题,我对原始代码做了一些修改,使其独立于平台,同时保留了总体思想,并希望保留大部分原始性能和其他特性。这里包含一个简单的MAC实现。这不是一个完美的解决方案,代码看上去有点难看,但它工作得很好,在我迄今为止测试过的所有平台上给出了相同的结果,而且它也应该比原来的更容易理解。
享受吧!当然,如果你还需要的话。
#include <stdint.h>
#include <stdbool.h>
#include <limits.h>
#include <string.h> // memcpy, memset and the others are defined here
// Platform-independent cyclic shifts. Rewrite as functions when needed.
#define BitsCount( val ) ( sizeof( val ) * CHAR_BIT )
#define Shift( val, steps ) ( steps % BitsCount( val ) )
#define ROL( val, steps ) ( ( val << Shift( val, steps ) ) | ( val >> ( BitsCount( val ) - Shift( val, steps ) ) ) )
#define ROR( val, steps ) ( ( val >> Shift( val, steps ) ) | ( val << ( BitsCount( val ) - Shift( val, steps ) ) ) )
void RaidenEncoder(const uint32_t key[4], const uint32_t data[2], uint32_t result[2])
{
uint32_t k[4];
uint32_t b0 = data[0], b1 = data[1];
register int8_t i;
k[0]=key[0]; k[1]=key[1]; k[2]=key[2]; k[3]=key[3];
for (i=0; i<16; i++) {
register uint32_t sk;
sk = k[i%4] = ((k[0]+k[1])+((k[2]+k[3])^ROL(k[0],k[2])));
b0 += ((sk+b1)<<9) ^ ((sk-b1)^((sk+b1)>>14));
b1 += ((sk+b0)<<9) ^ ((sk-b0)^((sk+b0)>>14));
}
result[0] = b0;
result[1] = b1;
}
void RaidenDecoder(const uint32_t key[4], const uint32_t data[2], uint32_t result[2])
{
register uint32_t b0 = data[0], b1 = data[1];
register int8_t i;
uint32_t k[4];
uint32_t subkeys[16];
k[0]=key[0]; k[1]=key[1]; k[2]=key[2]; k[3]=key[3];
//Prepare subkeys
for(i=0; i<16; i++) {
k[i%4]=((k[0]+k[1])+((k[2]+k[3])^ROL(k[0],k[2])));
subkeys[i]=k[i%4];
}
for(i=15; i>=0; i--) {
//Process is applied in the inverse order
b1 -= ((subkeys[i]+b0)<<9)^((subkeys[i]-b0)^((subkeys[i]+b0)>>14));
b0 -= ((subkeys[i]+b1)<<9)^((subkeys[i]-b1)^((subkeys[i]+b1)>>14));
}
result[0]=b0;
result[1]=b1;
}
// Message authentication code checking function (64-bit digests and 128-bit keys are used).
bool CheckRaidenMAC(const uint32_t key[4], const uint32_t mac[2], uint8_t* data, const uint32_t length)
{
register uint32_t i;
uint32_t stage_result[2] = {0,0}; // We use fixed all-zero init vector
uint32_t encoder_input[2] = {0,0};
uint8_t remainder_length = length%8;
// Process data length information as the first stage
encoder_input[0] = length;
RaidenEncoder(key, encoder_input, stage_result);
// Calculate the MAC
for (i=0;i<length;i+=8) {
encoder_input[0] = stage_result[0] ^ *((uint32_t*)&data[i]);
encoder_input[1] = stage_result[1] ^ *((uint32_t*)&data[i+1]);
RaidenEncoder(key, encoder_input, stage_result);
}
// Check if we need to add padding to calculate the final stage
if (remainder_length) {
// Load the data remainder
memcpy(&encoder_input[0], &data[length-remainder_length], remainder_length);
// Put in zero padding
memset(&encoder_input[remainder_length], 0, 8-remainder_length);
// Process the last stage
encoder_input[0] ^= stage_result[0];
encoder_input[1] ^= stage_result[1];
RaidenEncoder(key, encoder_input, stage_result);
}
// Check if our digest matches the provided one
return ((mac[0] == stage_result[0]) && (mac[1] == stage_result[1]));
}如果需要的话,void GetRaidenMAC(const uint32_t key[4], uint32_t* mac, uint8_t* data, const uint32_t length)的实现应该是直接从上面的代码中获得的。
另外,请注意,Raiden是块密码,因此它被设计为独立处理128位数据的固定块。如果您需要加密不同或可变数量的数据,那么还需要编写另一个函数,将数据分割成16字节的块,并将密码函数逐个提供给单独的数据块(可能还需要使用前面的密码结果对它们进行XOR-),并在需要时将零填充添加到最后一个块中。但是,它将是从Raiden块密码派生出来的新的流密码,它的性能将根据您的特定实现而有所不同。编写这样的函数有很多种方法。
https://stackoverflow.com/questions/26854227
复制相似问题