首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >理解raiden密码:代码中未定义的行为?

理解raiden密码:代码中未定义的行为?
EN

Stack Overflow用户
提问于 2014-11-10 22:29:38
回答 2查看 163关注 0票数 0

看了看雷登密码,我不确定我是否理解密码:

代码语言:javascript
复制
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呢?

或者这只是一个半途而废的算法,我甚至不应该去看它?我在考虑用它加密真实的数据

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-11-11 00:11:35

不知道为什么你对这个特殊的密码感兴趣,它似乎没有得到太多的发展。从可用的零碎信息来看,似乎通过key3的密钥被视为32位的数量。如果是这样,则未定义表达式(k[0]<<k[2]),如C标准中的以下子句所明确表示的那样:

如果右操作数的值为负值,或大于或等于提升的左操作数的宽度,则行为未定义。

事实上,多年来,我看到了两种不同的移位量行为,它们“大于或等于左操作数的宽度”。

  1. 结果是零。
  2. 右操作数被缩小,表示左操作数的宽度,并通过这个减少的数量发生移位。

它确实是不可移植的,应该被认为是一个错误。最有可能的是,作者打算行为#2。@chux的评论建议使用uint32_t而不是未签名的long,这也是有意义的。

票数 2
EN

Stack Overflow用户

发布于 2021-02-19 18:59:03

据我所知,Raiden是一个OK算法,没有已知的陷阱,但它没有经过真正的测试,也没有标准化。它的工作原理非常类似于它的其他类别的密码,它应该与他们一样,但很难确定。我在一些非关键应用程序中使用过几次,在这些应用程序中,至少有一些数据真实性保证,但没有对它的实际要求,这是非常好的。

该算法唯一的缺点是,它的推荐实现只在C中提供,它使用按位移位的溢出操作,根据编译器( GCC、IAR、Keil、.的不同版本)、平台上(GCC for x86和ARM给出类似的组装指令,但它们在实际硬件上的执行结果不同)和选择的编程语言(C、Java、D和C++实现可以不同的工作方式),因此不同的设备和程序很有可能对函数的结果有不同的看法。

为了克服这个问题,我对原始代码做了一些修改,使其独立于平台,同时保留了总体思想,并希望保留大部分原始性能和其他特性。这里包含一个简单的MAC实现。这不是一个完美的解决方案,代码看上去有点难看,但它工作得很好,在我迄今为止测试过的所有平台上给出了相同的结果,而且它也应该比原来的更容易理解。

享受吧!当然,如果你还需要的话。

代码语言:javascript
复制
#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块密码派生出来的新的流密码,它的性能将根据您的特定实现而有所不同。编写这样的函数有很多种方法。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26854227

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档