首页 > 解决方案 > RC6 实施给出了不希望的结果

问题描述

我正在尝试从论文中获得 RC6 实现。我已经仔细检查了论文中的算法,虽然我怀疑是密钥调度,但不确定我哪里出错了。

我目前的输出是这样的:

平原:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

密钥:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

加密:30 48 87 4e 00 69 ff 12 da 49 ad 9c 50 8a 0c 96

解密:80 53 4a d9 78 b9 37 54 64 8f d4 1d e0 10 56 5d

试图从论文中获得第一个测试向量:

明文 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

用户密钥 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

密文 8f c3 a5 36 56 b1 f7 78 c1 29 df 4e 98 48 a4 1e

#pragma once

#include <cmath>
#include <cstdio>
#include <vector>
#include <limits>

#include "types.h"

using std::max;
using std::ceil;
using std::pow;
using std::vector;
using std::numeric_limits;

// Binary expansion of e - 2
template<class T> static const T P = 
    T(ceil((M_E - 2) * pow(2, numeric_limits<T>::digits)));
// Binary expansion of ϕ - 1 where ϕ is the golden ratio
template<class T> static const T Q = 
    T(((1.618033988749895 - 1) * pow(2, numeric_limits<T>::digits)));

class rc6 {
private:
    
    // Used for indices on blocks to match paper
    enum {
        A = 0, 
        B = 1, 
        C = 2, 
        D = 3
    };

    static const unsigned MAX_KEY_LEN = 2040;
        
    /**
    * Rotate a N-bit value left
    * @param word: value to rotate
    * @param shift: bits to roll
    */
    template<class T> static inline T rol(T word, unsigned shift)
    {
        return (word << shift) | (word >> (numeric_limits<T>::digits - shift));
    }

    /**
    * Rotate a N-bit value right
    * @param word: value to rotate
    * @param shift: bits to roll
    */
    template<class T> static inline T ror(T word, unsigned shift)
    {
        return (word >> shift) | (word << (numeric_limits<T>::digits - shift));
    }
    
    /**
    * Create key schedule @S from input @key
    * @param key: key bytes
    * @param S: destination for key schedule
    * @param r: number of rounds
    */
    template<class T> static void key_schedule(vector<u8>& key, vector<T>& S, unsigned r = 20) {
        // The user supplies a key of b bytes
        unsigned b = key.size() * sizeof(T);
        unsigned b_bits = b * 8;
        
        if (b > MAX_KEY_LEN)
            fprintf(stderr, "ERROR: Key can't be greater than 2040 bits, got %u.\n", b_bits);
        
        // Sufficient zero bytes are appended to give a key length equal to a non-zero 
        // integral number of words
        for ( ; key.size() % sizeof(T) != 0; b++)
            key.push_back(0x00);
        
        // key bytes are then loaded in little-endian fashion into an array of c w-bit 
        // words L[0], ..., L[c - 1]
        const unsigned c = key.size();
        vector<T> L(key.data(), static_cast<u8*>(key.data()) + b);
        
        const unsigned v = 3 * max(c, 2 * r + 4);
        unsigned i = 0, j = 0;

        S[0] = P<T>;
        for (i = 1; i < 2 * r + 3; i++)
            S[i] = S[i - 1] + Q<T>;
        
        i = 0;
        unsigned A = 0, B = 0;
        for (unsigned s = 1; s <= v; s++) {
            A = S[i] = rol(S[i] + A + B, 3);
            B = L[j] = rol(L[j] + A + B, A + B);
            i = (i + 1) % (2 * r + 4);
            j = (j + 1) % c;
        }
    }
    
public:
    /**
    * Encrypt @plaintext using @key for @r rounds
    * @param plaintext: plain text to encrypt
    * @param key: key bytes
    * @param r: number of rounds
    */
    template<class T> static void encrypt(vector<T>& plaintext, vector<u8>& key, unsigned r = 20)
    {
        vector<T> S(2 * r + 4);
        key_schedule(key, S, r);
        unsigned w = numeric_limits<T>::digits;

        for (auto block = plaintext.begin(); block != plaintext.end(); block += 4) {
            block[B] += S[0];
            block[D] += S[1];

            for (unsigned i = 1; i <= r; i++) {
                T t = rol(block[B] * (2 * block[B] + 1), log2(w));
                T u = rol(block[D] * (2 * block[D] + 1), log2(w));
                block[A] = rol((block[A] ^ t), u) + S[2 * i];
                block[C] = rol((block[C] ^ u), t) + S[2 * i + 1];
                T a = block[A];
                block[A] = block[B];
                block[B] = block[C];
                block[C] = block[D];
                block[D] = a;
            }
            block[A] += S[2 * r + 2];
            block[C] += S[2 * r + 3];
        }
    }

    /**
    * Decrypt @ciphertext using @key for @r rounds
    * @param plaintext: plain text to encrypt
    * @param key: key bytes
    * @param r: number of rounds
    */
    template<class T> static void decrypt(vector<T>& ciphertext, vector<u8>& key, unsigned r = 20)
    {
        vector<T> S(2 * r + 4);
        key_schedule(key, S, r);
        unsigned w = std::numeric_limits<T>::digits;
        
        for (auto block = ciphertext.begin(); block != ciphertext.end(); block += 4) {
            for (unsigned i = r; i > 0; i--) {
                T d = block[D];
                block[D] = block[C];
                block[C] = block[B];
                block[B] = block[A];
                block[A] = d;
                T u = rol(block[D] * (2 * block[D] + 1), log2(w));
                T t = rol(block[B] * (2 * block[B] + 1), log2(w));
                block[C] = ror(block[C] - S[2 * i + 1], t) ^ u;
                block[A] = ror(block[A] - S[2 * i], u) ^ t;
            }
            
            block[D] -= S[1];
            block[B] -= S[0];
        }
    }
};

标签: c++cryptography

解决方案


推荐阅读