📄 aes.cpp
字号:
/****************************************************************
* *
* This program is part of an implementation of the block *
* cipher RC6(TM) that is being submitted to NIST as a *
* candidate for the AES. *
* *
* Ronald L. Rivest and RSA Laboratories, the submitters of *
* RC6, retain all rights to RC6 and to this code, except for *
* those which NIST requires to be waived for submissions. *
* *
* Copyright (C) 1998 RSA Data Security, Inc. *
* *
****************************************************************/
/* This file contains a reference implementation of RC6 in C. */
/*注:Rc6ComputeKeySchedule();Rc6EncryptBlock();Rc6DecryptBlock();
这三个函数已经实现了RC6层密钥生成、加脱密的功能;*/
#include <string.h>
#include <ctype.h>
#include "aes.h"
/* The "magic constants" for RC6 with 32-bit wordsize */
#define P32 0xb7e15163
#define Q32 0x9e3779b9
/* Macro for left-rotating a 32-bit dword by some amount */
#define ROTL(W,c) (((W) << ((c) & 0x1f)) | ((W) >> (32-((c) & 0x1f))))
/* Macro for right-rotating a 32-bit dword by some amount */
#define ROTR(W,c) (((W) >> ((c) & 0x1f)) | ((W) << (32-((c) & 0x1f))))
/*
* Here we implement a few general utility functions
*/
/*
* Load an unsigned long as a little-endian sequence of 4 bytes
*/
static unsigned long LoadDword(BYTE* ptr)
{
return (((unsigned long) *ptr)+
(((unsigned long) *(ptr+1)) << 8)+
(((unsigned long) *(ptr+2)) << 16)+
(((unsigned long) *(ptr+3)) << 24));
}
/*
* Store an unsigned long as a little-endian sequence of 4 bytes
*/
static void StoreDword(unsigned long dword, BYTE* ptr)
{
*ptr = (BYTE) dword;
*(ptr+1) = (BYTE) (dword >> 8);
*(ptr+2) = (BYTE) (dword >> 16);
*(ptr+3) = (BYTE) (dword >> 24);
}
/*
* ConvertDigitToNumber() converts a single ASCII hexadecimal digit
* to its numeric equivalent in the range 0x0-0xf.
*/
static BYTE ConvertDigitToNumber(char digit)
{
if (isdigit(digit))
return ((BYTE) (digit-'0'));
if (islower(digit))
return ((BYTE) (digit-'a'+0xa));
/* Apparently, it's an uppercase letter */
return ((BYTE) (digit-'A'+0xa));
}
/*
* ConvertDigitsToBytes() converts a sequence of pairs of ASCII hex
* digits into a sequence of bytes. It takes an argument, n, which
* specifies how many bytes will be produced: 2n hex digits get
* converted to n bytes.
*/
static void ConvertDigitsToBytes(char* digits, BYTE* bytes, int n)
{
int i;
for (i = 0; i < n*2; i += 2) {
BYTE msn = ConvertDigitToNumber(digits[i]);
BYTE lsn = ConvertDigitToNumber(digits[i+1]);
bytes[i/2] = (BYTE) ((msn << 4) | lsn);
}
}
/*
* The next three functions-- Rc6ComputeKeySchedule(), Rc6EncryptBlock(),
* and Rc6DecryptBlock()-- form the bottom-level implementation of RC6.
*/
/*
* Rc6ComputeKeySchedule() computes a key schedule from a variable-length
* key. It does *not* properly test the length of the key in advance, so
* a key passed to it should not have an out-of-range length. Valid key
* lengths are 0-255 bytes.
*
* The key passed to RC6ComputeKeySchedule() is a sequence of bytes, NOT
* an ASCII string.
*
* Rc6ComputeKeySchedule() places the schedule it computes in an array
* of 2+2*ROUNDS+2 = 44 dwords specified by a pointer, S, that is input.
*/
static void Rc6ComputeKeySchedule(BYTE* key, int keyLengthInBytes,
unsigned long* S)
{
unsigned long L[(255+4-1)/4];
const int t = 2+2*ROUNDS+2;
int count;
int u;
int i,j;
unsigned long A,B;
int startOfExtraDword, numberOfExtraBytes;
/* Compute number of dwords taken up by key */
int c = (keyLengthInBytes+4-1)/4;
/* Special case: if the key is 0 bytes, then we'll start out with a
* single element with the value 0 in the array of key dwords */
if (c == 0)c = 1;
/* Zero out array of key dwords */
for (count = 0; count < c; count++)
L[count] = 0;
/* Load all the key bytes into the array of key dwords, with the
* possible exception of the final 1-3 bytes */
for (count = 0; count < keyLengthInBytes/4; count++)
L[count] = LoadDword(key+count*4);
printf("**********************密钥扩展*********************\n");
printf("L[],0--4\n");
for(i=0;i<c;i++)printf("%08x ",L[i]);printf("\n\n");
/* Load any extra key bytes at the end into the last dword */
startOfExtraDword = keyLengthInBytes & 0xfffffffc;
numberOfExtraBytes = keyLengthInBytes & 0x3;
if (numberOfExtraBytes > 0) {
L[c-1] = (unsigned long) key[startOfExtraDword];
if (numberOfExtraBytes > 1) {
L[c-1] |= (((unsigned long) key[startOfExtraDword+1]) << 8);
if (numberOfExtraBytes > 2)
L[c-1] |= (((unsigned long) key[startOfExtraDword+2]) << 16);
}
}
/* Initialize key schedule array */
S[0] = P32;
for (count = 1; count < t; count++)
S[count] = S[count-1]+Q32;
printf("S[0]=Pw S[i]=S[i-1]+Qw\n");
for(i=0;i<t;i++){printf("%08x ",S[i]);if(i%8==7)printf("\n");}printf("\n\n");
/* The number of passes in the key schedule set-up algorithm is equal to
* 3 times the size of whichever is larger: the array of key dwords, or
* the array of key schedule dwords that we're computing. */
u = 3*((c>t) ? c : t);
i = j = 0;
A = B = 0;
/* Mix the key into the key schedule array over the course of u rounds */
for (count = 1; count <= u; count++) {
unsigned long sum;
sum = A+B;
S[i] += sum;
A = S[i] = ROTL(S[i], 3);
sum = A+B;
L[j] += sum;
B = L[j] = ROTL(L[j], sum);
i = (i+1) % t;
j = (j+1) % c;
}
printf("经最终变换后的加密密钥\n");
for(i=0;i<t;i++){printf("%08x ",S[i]);if(i%8==7)printf("\n");}printf("\n\n");
}
/*
* Rc6EncryptBlock() encrypts a single [16-byte] block of plaintext.
* The key schedule to be used is passed in as a pointer, S, to the
* array of 44 dwords of which the key schedule is comprised.
*/
static void Rc6EncryptBlock(unsigned long* S,
BYTE* plaintext, BYTE* ciphertext)
{
int i;
/* Load A, B, C, and D registers from plaintext */
unsigned long A = LoadDword(plaintext);
unsigned long B = LoadDword(plaintext+4);
unsigned long C = LoadDword(plaintext+8);
unsigned long D = LoadDword(plaintext+12);
printf("***********************Encrypt start********************\n");
printf("A=%08x B=%08x C=%08x D=%08x \n",A,B,C,D);
/* Do pseudo-round #0: pre-whitening of B and D */
B += S[0];
D += S[1];
/* Perform round #1, #2, ..., #ROUNDS of encryption */
for (i = 1; i <= ROUNDS; i++)
{
unsigned long t, u;
t = B*(2*B+1);
t = ROTL(t, 5);
u = D*(2*D+1);
u = ROTL(u, 5);
A ^= t;
A = ROTL(A, u);
A += S[2*i];
C ^= u;
C = ROTL(C, t);
C += S[2*i+1];
printf("t=%08x u=%08x A=%08x C=%08x \n",t,u,A,C);
{
unsigned long temp = A;
A = B;
B = C;
C = D;
D = temp;
}
printf("A=%08x B=%08x C=%08x D=%08x \n",A,B,C,D);printf("\n");
}
/* Do pseudo-round #(ROUNDS+1): post-whitening of A and C */
A += S[2*ROUNDS+2];
C += S[2*ROUNDS+3];
/* Store A, B, C, and D registers to ciphertext */
StoreDword(A, ciphertext);
StoreDword(B, ciphertext+4);
StoreDword(C, ciphertext+8);
StoreDword(D, ciphertext+12);
}
/*
* Rc6DecryptBlock() decrypts a single [16-byte] block of ciphertext.
* The key schedule to be used is passed in as a pointer ("S") to the
* array of 44 dwords of which the key schedule is comprised.
*/
static void Rc6DecryptBlock(unsigned long* S,
BYTE* ciphertext, BYTE* plaintext)
{
int i;
/* Load A, B, C, and D registers from ciphertext */
unsigned long A = LoadDword(ciphertext);
unsigned long B = LoadDword(ciphertext+4);
unsigned long C = LoadDword(ciphertext+8);
unsigned long D = LoadDword(ciphertext+12);
/* Undo pseudo-round #(ROUNDS+1): post-whitening of A and C */
C -= S[2*ROUNDS+3];
A -= S[2*ROUNDS+2];
/* Undo round #ROUNDS, ..., #2, #1 of encryption */
for (i = ROUNDS; i >= 1; i--) {
unsigned long t, u;
{
unsigned long temp = D;
D = C;
C = B;
B = A;
A = temp;
}
t = B*(2*B+1);
t = ROTL(t, 5);
u = D*(2*D+1);
u = ROTL(u, 5);
C -= S[2*i+1];
C = ROTR(C, t);
C ^= u;
A -= S[2*i];
A = ROTR(A, u);
A ^= t;
}
/* Undo pseudo-round #0: pre-whitening of B and D */
D -= S[1];
B -= S[0];
/* Store A, B, C, and D registers to plaintext */
StoreDword(A, plaintext);
StoreDword(B, plaintext+4);
StoreDword(C, plaintext+8);
StoreDword(D, plaintext+12);
}
/*
* The six functions below add modes (ECB, CBC, and 1-bit CFB) to the
* simple block cipher functionality implemented above.
*/
/*
* Rc6EncryptEcb() encrypts a specified number of blocks in ECB mode.
*/
static void Rc6EncryptEcb(unsigned long* S, int numberOfBlocks,
BYTE* plaintext, BYTE* ciphertext)
{
for ( ; numberOfBlocks-- > 0; plaintext += 16, ciphertext += 16)
/* Encrypt block */
Rc6EncryptBlock(S, plaintext, ciphertext);
}
/*
* Rc6DecryptEcb() decrypts a specified number of blocks in ECB mode.
*/
static void Rc6DecryptEcb(unsigned long* S, int numberOfBlocks,
BYTE* ciphertext, BYTE* plaintext)
{
for ( ; numberOfBlocks-- > 0; ciphertext += 16, plaintext += 16)
/* Decrypt block */
Rc6DecryptBlock(S, ciphertext, plaintext);
}
/*
* Rc6EncryptCbc() encrypts a specified number of blocks in CBC mode.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -