Squashed 'lib/crypto-algorithms/' content from commit 100f4ff

git-subtree-dir: lib/crypto-algorithms
git-subtree-split: 100f4ff91b5a5b31a84b3999365c3058df6251ea
logging_enabled
Mark Haines 2015-02-26 16:43:06 +00:00
commit c61e5359cb
31 changed files with 3656 additions and 0 deletions

17
README.md Normal file
View File

@ -0,0 +1,17 @@
crypto-algorithms
=================
About
---
These are basic implementations of standard cryptography algorithms, written by Brad Conte (brad@bradconte.com) from scratch and without any cross-licensing. They exist to provide publically accessible, restriction-free implementations of popular cryptographic algorithms, like AES and SHA-1. These are primarily intended for educational and pragmatic purposes (such as comparing a specification to actual implementation code, or for building an internal application that computes test vectors for a product). The algorithms have been tested against standard test vectors.
This code is released into the public domain free of any restrictions. The author requests acknowledgement if the code is used, but does not require it. This code is provided free of any liability and without any quality claims by the author.
Note that these are *not* cryptographically secure implementations. They have no resistence to side-channel attacks and should not be used in contexts that need cryptographically secure implementations.
These algorithms are not optimized for speed or space. They are primarily designed to be easy to read, although some basic optimization techniques have been employed.
Building
---
The source code for each algorithm will come in a pair of a source code file and a header file. There should be no inter-header file dependencies, no additional libraries, no platform-specific header files, or any other complicating matters. Compiling them should be as easy as adding the relevent source code to the project.

1072
aes.c Normal file

File diff suppressed because it is too large Load Diff

123
aes.h Normal file
View File

@ -0,0 +1,123 @@
/*********************************************************************
* Filename: aes.h
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Defines the API for the corresponding AES implementation.
*********************************************************************/
#ifndef AES_H
#define AES_H
/*************************** HEADER FILES ***************************/
#include <stddef.h>
/****************************** MACROS ******************************/
#define AES_BLOCK_SIZE 16 // AES operates on 16 bytes at a time
/**************************** DATA TYPES ****************************/
typedef unsigned char BYTE; // 8-bit byte
typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines
/*********************** FUNCTION DECLARATIONS **********************/
///////////////////
// AES
///////////////////
// Key setup must be done before any AES en/de-cryption functions can be used.
void aes_key_setup(const BYTE key[], // The key, must be 128, 192, or 256 bits
WORD w[], // Output key schedule to be used later
int keysize); // Bit length of the key, 128, 192, or 256
void aes_encrypt(const BYTE in[], // 16 bytes of plaintext
BYTE out[], // 16 bytes of ciphertext
const WORD key[], // From the key setup
int keysize); // Bit length of the key, 128, 192, or 256
void aes_decrypt(const BYTE in[], // 16 bytes of ciphertext
BYTE out[], // 16 bytes of plaintext
const WORD key[], // From the key setup
int keysize); // Bit length of the key, 128, 192, or 256
///////////////////
// AES - CBC
///////////////////
int aes_encrypt_cbc(const BYTE in[], // Plaintext
size_t in_len, // Must be a multiple of AES_BLOCK_SIZE
BYTE out[], // Ciphertext, same length as plaintext
const WORD key[], // From the key setup
int keysize, // Bit length of the key, 128, 192, or 256
const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long
// Only output the CBC-MAC of the input.
int aes_encrypt_cbc_mac(const BYTE in[], // plaintext
size_t in_len, // Must be a multiple of AES_BLOCK_SIZE
BYTE out[], // Output MAC
const WORD key[], // From the key setup
int keysize, // Bit length of the key, 128, 192, or 256
const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long
///////////////////
// AES - CTR
///////////////////
void increment_iv(BYTE iv[], // Must be a multiple of AES_BLOCK_SIZE
int counter_size); // Bytes of the IV used for counting (low end)
void aes_encrypt_ctr(const BYTE in[], // Plaintext
size_t in_len, // Any byte length
BYTE out[], // Ciphertext, same length as plaintext
const WORD key[], // From the key setup
int keysize, // Bit length of the key, 128, 192, or 256
const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long
void aes_decrypt_ctr(const BYTE in[], // Ciphertext
size_t in_len, // Any byte length
BYTE out[], // Plaintext, same length as ciphertext
const WORD key[], // From the key setup
int keysize, // Bit length of the key, 128, 192, or 256
const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long
///////////////////
// AES - CCM
///////////////////
// Returns True if the input parameters do not violate any constraint.
int aes_encrypt_ccm(const BYTE plaintext[], // IN - Plaintext.
WORD plaintext_len, // IN - Plaintext length.
const BYTE associated_data[], // IN - Associated Data included in authentication, but not encryption.
unsigned short associated_data_len, // IN - Associated Data length in bytes.
const BYTE nonce[], // IN - The Nonce to be used for encryption.
unsigned short nonce_len, // IN - Nonce length in bytes.
BYTE ciphertext[], // OUT - Ciphertext, a concatination of the plaintext and the MAC.
WORD *ciphertext_len, // OUT - The length of the ciphertext, always plaintext_len + mac_len.
WORD mac_len, // IN - The desired length of the MAC, must be 4, 6, 8, 10, 12, 14, or 16.
const BYTE key[], // IN - The AES key for encryption.
int keysize); // IN - The length of the key in bits. Valid values are 128, 192, 256.
// Returns True if the input parameters do not violate any constraint.
// Use mac_auth to ensure decryption/validation was preformed correctly.
// If authentication does not succeed, the plaintext is zeroed out. To overwride
// this, call with mac_auth = NULL. The proper proceedure is to decrypt with
// authentication enabled (mac_auth != NULL) and make a second call to that
// ignores authentication explicitly if the first call failes.
int aes_decrypt_ccm(const BYTE ciphertext[], // IN - Ciphertext, the concatination of encrypted plaintext and MAC.
WORD ciphertext_len, // IN - Ciphertext length in bytes.
const BYTE assoc[], // IN - The Associated Data, required for authentication.
unsigned short assoc_len, // IN - Associated Data length in bytes.
const BYTE nonce[], // IN - The Nonce to use for decryption, same one as for encryption.
unsigned short nonce_len, // IN - Nonce length in bytes.
BYTE plaintext[], // OUT - The plaintext that was decrypted. Will need to be large enough to hold ciphertext_len - mac_len.
WORD *plaintext_len, // OUT - Length in bytes of the output plaintext, always ciphertext_len - mac_len .
WORD mac_len, // IN - The length of the MAC that was calculated.
int *mac_auth, // OUT - TRUE if authentication succeeded, FALSE if it did not. NULL pointer will ignore the authentication.
const BYTE key[], // IN - The AES key for decryption.
int keysize); // IN - The length of the key in BITS. Valid values are 128, 192, 256.
///////////////////
// Test functions
///////////////////
int aes_test();
int aes_ecb_test();
int aes_cbc_test();
int aes_ctr_test();
int aes_ccm_test();
#endif // AES_H

276
aes_test.c Normal file
View File

@ -0,0 +1,276 @@
/*********************************************************************
* Filename: aes_test.c
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Performs known-answer tests on the corresponding AES
implementation. These tests do not encompass the full
range of available test vectors and are not sufficient
for FIPS-140 certification. However, if the tests pass
it is very, very likely that the code is correct and was
compiled properly. This code also serves as
example usage of the functions.
*********************************************************************/
/*************************** HEADER FILES ***************************/
#include <stdio.h>
#include <memory.h>
#include "aes.h"
/*********************** FUNCTION DEFINITIONS ***********************/
void print_hex(BYTE str[], int len)
{
int idx;
for(idx = 0; idx < len; idx++)
printf("%02x", str[idx]);
}
int aes_ecb_test()
{
WORD key_schedule[60], idx;
BYTE enc_buf[128];
BYTE plaintext[2][16] = {
{0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96,0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a},
{0xae,0x2d,0x8a,0x57,0x1e,0x03,0xac,0x9c,0x9e,0xb7,0x6f,0xac,0x45,0xaf,0x8e,0x51}
};
BYTE ciphertext[2][16] = {
{0xf3,0xee,0xd1,0xbd,0xb5,0xd2,0xa0,0x3c,0x06,0x4b,0x5a,0x7e,0x3d,0xb1,0x81,0xf8},
{0x59,0x1c,0xcb,0x10,0xd4,0x10,0xed,0x26,0xdc,0x5b,0xa7,0x4a,0x31,0x36,0x28,0x70}
};
BYTE key[1][32] = {
{0x60,0x3d,0xeb,0x10,0x15,0xca,0x71,0xbe,0x2b,0x73,0xae,0xf0,0x85,0x7d,0x77,0x81,0x1f,0x35,0x2c,0x07,0x3b,0x61,0x08,0xd7,0x2d,0x98,0x10,0xa3,0x09,0x14,0xdf,0xf4}
};
int pass = 1;
// Raw ECB mode.
//printf("* ECB mode:\n");
aes_key_setup(key[0], key_schedule, 256);
//printf( "Key : ");
//print_hex(key[0], 32);
for(idx = 0; idx < 2; idx++) {
aes_encrypt(plaintext[idx], enc_buf, key_schedule, 256);
//printf("\nPlaintext : ");
//print_hex(plaintext[idx], 16);
//printf("\n-encrypted to: ");
//print_hex(enc_buf, 16);
pass = pass && !memcmp(enc_buf, ciphertext[idx], 16);
aes_decrypt(ciphertext[idx], enc_buf, key_schedule, 256);
//printf("\nCiphertext : ");
//print_hex(ciphertext[idx], 16);
//printf("\n-decrypted to: ");
//print_hex(enc_buf, 16);
pass = pass && !memcmp(enc_buf, plaintext[idx], 16);
//printf("\n\n");
}
return(pass);
}
int aes_cbc_test()
{
WORD key_schedule[60];
BYTE enc_buf[128];
BYTE plaintext[1][32] = {
{0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96,0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a,0xae,0x2d,0x8a,0x57,0x1e,0x03,0xac,0x9c,0x9e,0xb7,0x6f,0xac,0x45,0xaf,0x8e,0x51}
};
BYTE ciphertext[2][32] = {
{0xf5,0x8c,0x4c,0x04,0xd6,0xe5,0xf1,0xba,0x77,0x9e,0xab,0xfb,0x5f,0x7b,0xfb,0xd6,0x9c,0xfc,0x4e,0x96,0x7e,0xdb,0x80,0x8d,0x67,0x9f,0x77,0x7b,0xc6,0x70,0x2c,0x7d}
};
BYTE iv[1][16] = {
{0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f}
};
BYTE key[1][32] = {
{0x60,0x3d,0xeb,0x10,0x15,0xca,0x71,0xbe,0x2b,0x73,0xae,0xf0,0x85,0x7d,0x77,0x81,0x1f,0x35,0x2c,0x07,0x3b,0x61,0x08,0xd7,0x2d,0x98,0x10,0xa3,0x09,0x14,0xdf,0xf4}
};
int pass = 1;
//printf("* CBC mode:\n");
aes_key_setup(key[0], key_schedule, 256);
//printf( "Key : ");
//print_hex(key[0], 32);
//printf("\nIV : ");
//print_hex(iv[0], 16);
aes_encrypt_cbc(plaintext[0], 32, enc_buf, key_schedule, 256, iv[0]);
//printf("\nPlaintext : ");
//print_hex(plaintext[0], 32);
//printf("\n-encrypted to: ");
//print_hex(enc_buf, 32);
//printf("\nCiphertext : ");
//print_hex(ciphertext[0], 32);
pass = pass && !memcmp(enc_buf, ciphertext[0], 32);
//printf("\n\n");
return(pass);
}
int aes_ctr_test()
{
WORD key_schedule[60];
BYTE enc_buf[128];
BYTE plaintext[1][32] = {
{0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96,0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a,0xae,0x2d,0x8a,0x57,0x1e,0x03,0xac,0x9c,0x9e,0xb7,0x6f,0xac,0x45,0xaf,0x8e,0x51}
};
BYTE ciphertext[1][32] = {
{0x60,0x1e,0xc3,0x13,0x77,0x57,0x89,0xa5,0xb7,0xa7,0xf5,0x04,0xbb,0xf3,0xd2,0x28,0xf4,0x43,0xe3,0xca,0x4d,0x62,0xb5,0x9a,0xca,0x84,0xe9,0x90,0xca,0xca,0xf5,0xc5}
};
BYTE iv[1][16] = {
{0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff},
};
BYTE key[1][32] = {
{0x60,0x3d,0xeb,0x10,0x15,0xca,0x71,0xbe,0x2b,0x73,0xae,0xf0,0x85,0x7d,0x77,0x81,0x1f,0x35,0x2c,0x07,0x3b,0x61,0x08,0xd7,0x2d,0x98,0x10,0xa3,0x09,0x14,0xdf,0xf4}
};
int pass = 1;
//printf("* CTR mode:\n");
aes_key_setup(key[0], key_schedule, 256);
//printf( "Key : ");
//print_hex(key[0], 32);
//printf("\nIV : ");
//print_hex(iv[0], 16);
aes_encrypt_ctr(plaintext[0], 32, enc_buf, key_schedule, 256, iv[0]);
//printf("\nPlaintext : ");
//print_hex(plaintext[0], 32);
//printf("\n-encrypted to: ");
//print_hex(enc_buf, 32);
pass = pass && !memcmp(enc_buf, ciphertext[0], 32);
aes_decrypt_ctr(ciphertext[0], 32, enc_buf, key_schedule, 256, iv[0]);
//printf("\nCiphertext : ");
//print_hex(ciphertext[0], 32);
//printf("\n-decrypted to: ");
//print_hex(enc_buf, 32);
pass = pass && !memcmp(enc_buf, plaintext[0], 32);
//printf("\n\n");
return(pass);
}
int aes_ccm_test()
{
int mac_auth;
WORD enc_buf_len;
BYTE enc_buf[128];
BYTE plaintext[3][32] = {
{0x20,0x21,0x22,0x23},
{0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f},
{0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37}
};
BYTE assoc[3][32] = {
{0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07},
{0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f},
{0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13}
};
BYTE ciphertext[3][32 + 16] = {
{0x71,0x62,0x01,0x5b,0x4d,0xac,0x25,0x5d},
{0xd2,0xa1,0xf0,0xe0,0x51,0xea,0x5f,0x62,0x08,0x1a,0x77,0x92,0x07,0x3d,0x59,0x3d,0x1f,0xc6,0x4f,0xbf,0xac,0xcd},
{0xe3,0xb2,0x01,0xa9,0xf5,0xb7,0x1a,0x7a,0x9b,0x1c,0xea,0xec,0xcd,0x97,0xe7,0x0b,0x61,0x76,0xaa,0xd9,0xa4,0x42,0x8a,0xa5,0x48,0x43,0x92,0xfb,0xc1,0xb0,0x99,0x51}
};
BYTE iv[3][16] = {
{0x10,0x11,0x12,0x13,0x14,0x15,0x16},
{0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17},
{0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b}
};
BYTE key[1][32] = {
{0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f}
};
int pass = 1;
//printf("* CCM mode:\n");
//printf("Key : ");
//print_hex(key[0], 16);
//print_hex(plaintext[0], 4);
//print_hex(assoc[0], 8);
//print_hex(ciphertext[0], 8);
//print_hex(iv[0], 7);
//print_hex(key[0], 16);
aes_encrypt_ccm(plaintext[0], 4, assoc[0], 8, iv[0], 7, enc_buf, &enc_buf_len, 4, key[0], 128);
//printf("\nNONCE : ");
//print_hex(iv[0], 7);
//printf("\nAssoc. Data : ");
//print_hex(assoc[0], 8);
//printf("\nPayload : ");
//print_hex(plaintext[0], 4);
//printf("\n-encrypted to: ");
//print_hex(enc_buf, enc_buf_len);
pass = pass && !memcmp(enc_buf, ciphertext[0], enc_buf_len);
aes_decrypt_ccm(ciphertext[0], 8, assoc[0], 8, iv[0], 7, enc_buf, &enc_buf_len, 4, &mac_auth, key[0], 128);
//printf("\n-Ciphertext : ");
//print_hex(ciphertext[0], 8);
//printf("\n-decrypted to: ");
//print_hex(enc_buf, enc_buf_len);
//printf("\nAuthenticated: %d ", mac_auth);
pass = pass && !memcmp(enc_buf, plaintext[0], enc_buf_len) && mac_auth;
aes_encrypt_ccm(plaintext[1], 16, assoc[1], 16, iv[1], 8, enc_buf, &enc_buf_len, 6, key[0], 128);
//printf("\n\nNONCE : ");
//print_hex(iv[1], 8);
//printf("\nAssoc. Data : ");
//print_hex(assoc[1], 16);
//printf("\nPayload : ");
//print_hex(plaintext[1], 16);
//printf("\n-encrypted to: ");
//print_hex(enc_buf, enc_buf_len);
pass = pass && !memcmp(enc_buf, ciphertext[1], enc_buf_len);
aes_decrypt_ccm(ciphertext[1], 22, assoc[1], 16, iv[1], 8, enc_buf, &enc_buf_len, 6, &mac_auth, key[0], 128);
//printf("\n-Ciphertext : ");
//print_hex(ciphertext[1], 22);
//printf("\n-decrypted to: ");
//print_hex(enc_buf, enc_buf_len);
//printf("\nAuthenticated: %d ", mac_auth);
pass = pass && !memcmp(enc_buf, plaintext[1], enc_buf_len) && mac_auth;
aes_encrypt_ccm(plaintext[2], 24, assoc[2], 20, iv[2], 12, enc_buf, &enc_buf_len, 8, key[0], 128);
//printf("\n\nNONCE : ");
//print_hex(iv[2], 12);
//printf("\nAssoc. Data : ");
//print_hex(assoc[2], 20);
//printf("\nPayload : ");
//print_hex(plaintext[2], 24);
//printf("\n-encrypted to: ");
//print_hex(enc_buf, enc_buf_len);
pass = pass && !memcmp(enc_buf, ciphertext[2], enc_buf_len);
aes_decrypt_ccm(ciphertext[2], 32, assoc[2], 20, iv[2], 12, enc_buf, &enc_buf_len, 8, &mac_auth, key[0], 128);
//printf("\n-Ciphertext : ");
//print_hex(ciphertext[2], 32);
//printf("\n-decrypted to: ");
//print_hex(enc_buf, enc_buf_len);
//printf("\nAuthenticated: %d ", mac_auth);
pass = pass && !memcmp(enc_buf, plaintext[2], enc_buf_len) && mac_auth;
//printf("\n\n");
return(pass);
}
int aes_test()
{
int pass = 1;
pass = pass && aes_ecb_test();
pass = pass && aes_cbc_test();
pass = pass && aes_ctr_test();
pass = pass && aes_ccm_test();
return(pass);
}
int main(int argc, char *argv[])
{
printf("AES Tests: %s\n", aes_test() ? "SUCCEEDED" : "FAILED");
return(0);
}

45
arcfour.c Normal file
View File

@ -0,0 +1,45 @@
/*********************************************************************
* Filename: arcfour.c
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Implementation of the ARCFOUR encryption algorithm.
Algorithm specification can be found here:
* http://en.wikipedia.org/wiki/RC4
*********************************************************************/
/*************************** HEADER FILES ***************************/
#include <stdlib.h>
#include "arcfour.h"
/*********************** FUNCTION DEFINITIONS ***********************/
void arcfour_key_setup(BYTE state[], const BYTE key[], int len)
{
int i, j;
BYTE t;
for (i = 0; i < 256; ++i)
state[i] = i;
for (i = 0, j = 0; i < 256; ++i) {
j = (j + state[i] + key[i % len]) % 256;
t = state[i];
state[i] = state[j];
state[j] = t;
}
}
void arcfour_generate_stream(BYTE state[], BYTE out[], size_t len)
{
int i, j;
size_t idx;
BYTE t;
for (idx = 0, i = 0, j = 0; idx < len; ++idx) {
i = (i + 1) % 256;
j = (j + state[i]) % 256;
t = state[i];
state[i] = state[j];
state[j] = t;
out[idx] = state[(state[i] + state[j]) % 256];
}
}

30
arcfour.h Normal file
View File

@ -0,0 +1,30 @@
/*********************************************************************
* Filename: arcfour.h
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Defines the API for the corresponding ARCFOUR implementation.
*********************************************************************/
#ifndef ARCFOUR_H
#define ARCFOUR_H
/*************************** HEADER FILES ***************************/
#include <stddef.h>
/**************************** DATA TYPES ****************************/
typedef unsigned char BYTE; // 8-bit byte
/*********************** FUNCTION DECLARATIONS **********************/
// Input: state - the state used to generate the keystream
// key - Key to use to initialize the state
// len - length of key in bytes (valid lenth is 1 to 256)
void arcfour_key_setup(BYTE state[], const BYTE key[], int len);
// Pseudo-Random Generator Algorithm
// Input: state - the state used to generate the keystream
// out - Must be allocated to be of at least "len" length
// len - number of bytes to generate
void arcfour_generate_stream(BYTE state[], BYTE out[], size_t len);
#endif // ARCFOUR_H

47
arcfour_test.c Normal file
View File

@ -0,0 +1,47 @@
/*********************************************************************
* Filename: arcfour_test.c
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Performs known-answer tests on the corresponding ARCFOUR
implementation. These tests do not encompass the full
range of available test vectors, however, if the tests
pass it is very, very likely that the code is correct
and was compiled properly. This code also serves as
example usage of the functions.
*********************************************************************/
/*************************** HEADER FILES ***************************/
#include <stdio.h>
#include <memory.h>
#include "arcfour.h"
/*********************** FUNCTION DEFINITIONS ***********************/
int rc4_test()
{
BYTE state[256];
BYTE key[3][10] = {{"Key"}, {"Wiki"}, {"Secret"}};
BYTE stream[3][10] = {{0xEB,0x9F,0x77,0x81,0xB7,0x34,0xCA,0x72,0xA7,0x19},
{0x60,0x44,0xdb,0x6d,0x41,0xb7},
{0x04,0xd4,0x6b,0x05,0x3c,0xa8,0x7b,0x59}};
int stream_len[3] = {10,6,8};
BYTE buf[1024];
int idx;
int pass = 1;
// Only test the output stream. Note that the state can be reused.
for (idx = 0; idx < 3; idx++) {
arcfour_key_setup(state, key[idx], strlen(key[idx]));
arcfour_generate_stream(state, buf, stream_len[idx]);
pass = pass && !memcmp(stream[idx], buf, stream_len[idx]);
}
return(pass);
}
int main()
{
printf("ARCFOUR tests: %s\n", rc4_test() ? "SUCCEEDED" : "FAILED");
return(0);
}

135
base64.c Normal file
View File

@ -0,0 +1,135 @@
/*********************************************************************
* Filename: base64.c
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Implementation of the Base64 encoding algorithm.
*********************************************************************/
/*************************** HEADER FILES ***************************/
#include <stdlib.h>
#include "base64.h"
/****************************** MACROS ******************************/
#define NEWLINE_INVL 76
/**************************** VARIABLES *****************************/
// Note: To change the charset to a URL encoding, replace the '+' and '/' with '*' and '-'
static const BYTE charset[]={"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"};
/*********************** FUNCTION DEFINITIONS ***********************/
BYTE revchar(char ch)
{
if (ch >= 'A' && ch <= 'Z')
ch -= 'A';
else if (ch >= 'a' && ch <='z')
ch = ch - 'a' + 26;
else if (ch >= '0' && ch <='9')
ch = ch - '0' + 52;
else if (ch == '+')
ch = 62;
else if (ch == '/')
ch = 63;
return(ch);
}
size_t base64_encode(const BYTE in[], BYTE out[], size_t len, int newline_flag)
{
size_t idx, idx2, blks, blk_ceiling, left_over, newline_count = 0;
blks = (len / 3);
left_over = len % 3;
if (out == NULL) {
idx2 = blks * 4 ;
if (left_over)
idx2 += 4;
if (newline_flag)
idx2 += len / 57; // (NEWLINE_INVL / 4) * 3 = 57. One newline per 57 input bytes.
}
else {
// Since 3 input bytes = 4 output bytes, determine out how many even sets of
// 3 bytes the input has.
blk_ceiling = blks * 3;
for (idx = 0, idx2 = 0; idx < blk_ceiling; idx += 3, idx2 += 4) {
out[idx2] = charset[in[idx] >> 2];
out[idx2 + 1] = charset[((in[idx] & 0x03) << 4) | (in[idx + 1] >> 4)];
out[idx2 + 2] = charset[((in[idx + 1] & 0x0f) << 2) | (in[idx + 2] >> 6)];
out[idx2 + 3] = charset[in[idx + 2] & 0x3F];
// The offical standard requires a newline every 76 characters.
// (Eg, first newline is character 77 of the output.)
if (((idx2 - newline_count + 4) % NEWLINE_INVL == 0) && newline_flag) {
out[idx2 + 4] = '\n';
idx2++;
newline_count++;
}
}
if (left_over == 1) {
out[idx2] = charset[in[idx] >> 2];
out[idx2 + 1] = charset[(in[idx] & 0x03) << 4];
out[idx2 + 2] = '=';
out[idx2 + 3] = '=';
idx2 += 4;
}
else if (left_over == 2) {
out[idx2] = charset[in[idx] >> 2];
out[idx2 + 1] = charset[((in[idx] & 0x03) << 4) | (in[idx + 1] >> 4)];
out[idx2 + 2] = charset[(in[idx + 1] & 0x0F) << 2];
out[idx2 + 3] = '=';
idx2 += 4;
}
}
return(idx2);
}
size_t base64_decode(const BYTE in[], BYTE out[], size_t len)
{
BYTE ch;
size_t idx, idx2, blks, blk_ceiling, left_over;
if (in[len - 1] == '=')
len--;
if (in[len - 1] == '=')
len--;
blks = len / 4;
left_over = len % 4;
if (out == NULL) {
if (len >= 77 && in[NEWLINE_INVL] == '\n') // Verify that newlines where used.
len -= len / (NEWLINE_INVL + 1);
blks = len / 4;
left_over = len % 4;
idx = blks * 3;
if (left_over == 2)
idx ++;
else if (left_over == 3)
idx += 2;
}
else {
blk_ceiling = blks * 4;
for (idx = 0, idx2 = 0; idx2 < blk_ceiling; idx += 3, idx2 += 4) {
if (in[idx2] == '\n')
idx2++;
out[idx] = (revchar(in[idx2]) << 2) | ((revchar(in[idx2 + 1]) & 0x30) >> 4);
out[idx + 1] = (revchar(in[idx2 + 1]) << 4) | (revchar(in[idx2 + 2]) >> 2);
out[idx + 2] = (revchar(in[idx2 + 2]) << 6) | revchar(in[idx2 + 3]);
}
if (left_over == 2) {
out[idx] = (revchar(in[idx2]) << 2) | ((revchar(in[idx2 + 1]) & 0x30) >> 4);
idx++;
}
else if (left_over == 3) {
out[idx] = (revchar(in[idx2]) << 2) | ((revchar(in[idx2 + 1]) & 0x30) >> 4);
out[idx + 1] = (revchar(in[idx2 + 1]) << 4) | (revchar(in[idx2 + 2]) >> 2);
idx += 2;
}
}
return(idx);
}

27
base64.h Normal file
View File

@ -0,0 +1,27 @@
/*********************************************************************
* Filename: base64.h
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Defines the API for the corresponding Base64 implementation.
*********************************************************************/
#ifndef BASE64_H
#define BASE64_H
/*************************** HEADER FILES ***************************/
#include <stddef.h>
/**************************** DATA TYPES ****************************/
typedef unsigned char BYTE; // 8-bit byte
/*********************** FUNCTION DECLARATIONS **********************/
// Returns the size of the output. If called with out = NULL, will just return
// the size of what the output would have been (without a terminating NULL).
size_t base64_encode(const BYTE in[], BYTE out[], size_t len, int newline_flag);
// Returns the size of the output. If called with out = NULL, will just return
// the size of what the output would have been (without a terminating NULL).
size_t base64_decode(const BYTE in[], BYTE out[], size_t len);
#endif // BASE64_H

54
base64_test.c Normal file
View File

@ -0,0 +1,54 @@
/*********************************************************************
* Filename: blowfish_test.c
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Performs known-answer tests on the corresponding Base64
implementation. These tests do not encompass the full
range of available test vectors, however, if the tests
pass it is very, very likely that the code is correct
and was compiled properly. This code also serves as
example usage of the functions.
*********************************************************************/
/*************************** HEADER FILES ***************************/
#include <stdio.h>
#include <memory.h>
#include "base64.h"
/*********************** FUNCTION DEFINITIONS ***********************/
int base64_test()
{
BYTE text[3][1024] = {{"fo"},
{"foobar"},
{"Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure."}};
BYTE code[3][1024] = {{"Zm8="},
{"Zm9vYmFy"},
{"TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz\nIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg\ndGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu\ndWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo\nZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4="}};
BYTE buf[1024];
size_t buf_len;
int pass = 1;
int idx;
for (idx = 0; idx < 3; idx++) {
buf_len = base64_encode(text[idx], buf, strlen(text[idx]), 1);
pass = pass && ((buf_len == strlen(code[idx])) &&
(buf_len == base64_encode(text[idx], NULL, strlen(text[idx]), 1)));
pass = pass && !strcmp(code[idx], buf);
memset(buf, 0, sizeof(buf));
buf_len = base64_decode(code[idx], buf, strlen(code[idx]));
pass = pass && ((buf_len == strlen(text[idx])) &&
(buf_len == base64_decode(code[idx], NULL, strlen(code[idx]))));
pass = pass && !strcmp(text[idx], buf);
}
return(pass);
}
int main()
{
printf("Base64 tests: %s\n", base64_test() ? "PASSED" : "FAILED");
return 0;
}

269
blowfish.c Normal file
View File

@ -0,0 +1,269 @@
/*********************************************************************
* Filename: blowfish.c
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Implementation of the Blowfish encryption algorithm.
Modes of operation (such as CBC) are not included.
Algorithm specification can be found here:
* http://www.schneier.com/blowfish.html
*********************************************************************/
/*************************** HEADER FILES ***************************/
#include <stdlib.h>
#include <memory.h>
#include "blowfish.h"
/****************************** MACROS ******************************/
#define F(x,t) t = keystruct->s[0][(x) >> 24]; \
t += keystruct->s[1][((x) >> 16) & 0xff]; \
t ^= keystruct->s[2][((x) >> 8) & 0xff]; \
t += keystruct->s[3][(x) & 0xff];
#define swap(r,l,t) t = l; l = r; r = t;
#define ITERATION(l,r,t,pval) l ^= keystruct->p[pval]; F(l,t); r^= t; swap(r,l,t);
/**************************** VARIABLES *****************************/
static const WORD p_perm[18] = {
0x243F6A88,0x85A308D3,0x13198A2E,0x03707344,0xA4093822,0x299F31D0,0x082EFA98,
0xEC4E6C89,0x452821E6,0x38D01377,0xBE5466CF,0x34E90C6C,0xC0AC29B7,0xC97C50DD,
0x3F84D5B5,0xB5470917,0x9216D5D9,0x8979FB1B
};
static const WORD s_perm[4][256] = { {
0xD1310BA6,0x98DFB5AC,0x2FFD72DB,0xD01ADFB7,0xB8E1AFED,0x6A267E96,0xBA7C9045,0xF12C7F99,
0x24A19947,0xB3916CF7,0x0801F2E2,0x858EFC16,0x636920D8,0x71574E69,0xA458FEA3,0xF4933D7E,
0x0D95748F,0x728EB658,0x718BCD58,0x82154AEE,0x7B54A41D,0xC25A59B5,0x9C30D539,0x2AF26013,
0xC5D1B023,0x286085F0,0xCA417918,0xB8DB38EF,0x8E79DCB0,0x603A180E,0x6C9E0E8B,0xB01E8A3E,
0xD71577C1,0xBD314B27,0x78AF2FDA,0x55605C60,0xE65525F3,0xAA55AB94,0x57489862,0x63E81440,
0x55CA396A,0x2AAB10B6,0xB4CC5C34,0x1141E8CE,0xA15486AF,0x7C72E993,0xB3EE1411,0x636FBC2A,
0x2BA9C55D,0x741831F6,0xCE5C3E16,0x9B87931E,0xAFD6BA33,0x6C24CF5C,0x7A325381,0x28958677,
0x3B8F4898,0x6B4BB9AF,0xC4BFE81B,0x66282193,0x61D809CC,0xFB21A991,0x487CAC60,0x5DEC8032,
0xEF845D5D,0xE98575B1,0xDC262302,0xEB651B88,0x23893E81,0xD396ACC5,0x0F6D6FF3,0x83F44239,
0x2E0B4482,0xA4842004,0x69C8F04A,0x9E1F9B5E,0x21C66842,0xF6E96C9A,0x670C9C61,0xABD388F0,
0x6A51A0D2,0xD8542F68,0x960FA728,0xAB5133A3,0x6EEF0B6C,0x137A3BE4,0xBA3BF050,0x7EFB2A98,
0xA1F1651D,0x39AF0176,0x66CA593E,0x82430E88,0x8CEE8619,0x456F9FB4,0x7D84A5C3,0x3B8B5EBE,
0xE06F75D8,0x85C12073,0x401A449F,0x56C16AA6,0x4ED3AA62,0x363F7706,0x1BFEDF72,0x429B023D,
0x37D0D724,0xD00A1248,0xDB0FEAD3,0x49F1C09B,0x075372C9,0x80991B7B,0x25D479D8,0xF6E8DEF7,
0xE3FE501A,0xB6794C3B,0x976CE0BD,0x04C006BA,0xC1A94FB6,0x409F60C4,0x5E5C9EC2,0x196A2463,
0x68FB6FAF,0x3E6C53B5,0x1339B2EB,0x3B52EC6F,0x6DFC511F,0x9B30952C,0xCC814544,0xAF5EBD09,
0xBEE3D004,0xDE334AFD,0x660F2807,0x192E4BB3,0xC0CBA857,0x45C8740F,0xD20B5F39,0xB9D3FBDB,
0x5579C0BD,0x1A60320A,0xD6A100C6,0x402C7279,0x679F25FE,0xFB1FA3CC,0x8EA5E9F8,0xDB3222F8,
0x3C7516DF,0xFD616B15,0x2F501EC8,0xAD0552AB,0x323DB5FA,0xFD238760,0x53317B48,0x3E00DF82,
0x9E5C57BB,0xCA6F8CA0,0x1A87562E,0xDF1769DB,0xD542A8F6,0x287EFFC3,0xAC6732C6,0x8C4F5573,
0x695B27B0,0xBBCA58C8,0xE1FFA35D,0xB8F011A0,0x10FA3D98,0xFD2183B8,0x4AFCB56C,0x2DD1D35B,
0x9A53E479,0xB6F84565,0xD28E49BC,0x4BFB9790,0xE1DDF2DA,0xA4CB7E33,0x62FB1341,0xCEE4C6E8,
0xEF20CADA,0x36774C01,0xD07E9EFE,0x2BF11FB4,0x95DBDA4D,0xAE909198,0xEAAD8E71,0x6B93D5A0,
0xD08ED1D0,0xAFC725E0,0x8E3C5B2F,0x8E7594B7,0x8FF6E2FB,0xF2122B64,0x8888B812,0x900DF01C,
0x4FAD5EA0,0x688FC31C,0xD1CFF191,0xB3A8C1AD,0x2F2F2218,0xBE0E1777,0xEA752DFE,0x8B021FA1,
0xE5A0CC0F,0xB56F74E8,0x18ACF3D6,0xCE89E299,0xB4A84FE0,0xFD13E0B7,0x7CC43B81,0xD2ADA8D9,
0x165FA266,0x80957705,0x93CC7314,0x211A1477,0xE6AD2065,0x77B5FA86,0xC75442F5,0xFB9D35CF,
0xEBCDAF0C,0x7B3E89A0,0xD6411BD3,0xAE1E7E49,0x00250E2D,0x2071B35E,0x226800BB,0x57B8E0AF,
0x2464369B,0xF009B91E,0x5563911D,0x59DFA6AA,0x78C14389,0xD95A537F,0x207D5BA2,0x02E5B9C5,
0x83260376,0x6295CFA9,0x11C81968,0x4E734A41,0xB3472DCA,0x7B14A94A,0x1B510052,0x9A532915,
0xD60F573F,0xBC9BC6E4,0x2B60A476,0x81E67400,0x08BA6FB5,0x571BE91F,0xF296EC6B,0x2A0DD915,
0xB6636521,0xE7B9F9B6,0xFF34052E,0xC5855664,0x53B02D5D,0xA99F8FA1,0x08BA4799,0x6E85076A
},{
0x4B7A70E9,0xB5B32944,0xDB75092E,0xC4192623,0xAD6EA6B0,0x49A7DF7D,0x9CEE60B8,0x8FEDB266,
0xECAA8C71,0x699A17FF,0x5664526C,0xC2B19EE1,0x193602A5,0x75094C29,0xA0591340,0xE4183A3E,
0x3F54989A,0x5B429D65,0x6B8FE4D6,0x99F73FD6,0xA1D29C07,0xEFE830F5,0x4D2D38E6,0xF0255DC1,
0x4CDD2086,0x8470EB26,0x6382E9C6,0x021ECC5E,0x09686B3F,0x3EBAEFC9,0x3C971814,0x6B6A70A1,
0x687F3584,0x52A0E286,0xB79C5305,0xAA500737,0x3E07841C,0x7FDEAE5C,0x8E7D44EC,0x5716F2B8,
0xB03ADA37,0xF0500C0D,0xF01C1F04,0x0200B3FF,0xAE0CF51A,0x3CB574B2,0x25837A58,0xDC0921BD,
0xD19113F9,0x7CA92FF6,0x94324773,0x22F54701,0x3AE5E581,0x37C2DADC,0xC8B57634,0x9AF3DDA7,
0xA9446146,0x0FD0030E,0xECC8C73E,0xA4751E41,0xE238CD99,0x3BEA0E2F,0x3280BBA1,0x183EB331,
0x4E548B38,0x4F6DB908,0x6F420D03,0xF60A04BF,0x2CB81290,0x24977C79,0x5679B072,0xBCAF89AF,
0xDE9A771F,0xD9930810,0xB38BAE12,0xDCCF3F2E,0x5512721F,0x2E6B7124,0x501ADDE6,0x9F84CD87,
0x7A584718,0x7408DA17,0xBC9F9ABC,0xE94B7D8C,0xEC7AEC3A,0xDB851DFA,0x63094366,0xC464C3D2,
0xEF1C1847,0x3215D908,0xDD433B37,0x24C2BA16,0x12A14D43,0x2A65C451,0x50940002,0x133AE4DD,
0x71DFF89E,0x10314E55,0x81AC77D6,0x5F11199B,0x043556F1,0xD7A3C76B,0x3C11183B,0x5924A509,
0xF28FE6ED,0x97F1FBFA,0x9EBABF2C,0x1E153C6E,0x86E34570,0xEAE96FB1,0x860E5E0A,0x5A3E2AB3,
0x771FE71C,0x4E3D06FA,0x2965DCB9,0x99E71D0F,0x803E89D6,0x5266C825,0x2E4CC978,0x9C10B36A,
0xC6150EBA,0x94E2EA78,0xA5FC3C53,0x1E0A2DF4,0xF2F74EA7,0x361D2B3D,0x1939260F,0x19C27960,
0x5223A708,0xF71312B6,0xEBADFE6E,0xEAC31F66,0xE3BC4595,0xA67BC883,0xB17F37D1,0x018CFF28,
0xC332DDEF,0xBE6C5AA5,0x65582185,0x68AB9802,0xEECEA50F,0xDB2F953B,0x2AEF7DAD,0x5B6E2F84,
0x1521B628,0x29076170,0xECDD4775,0x619F1510,0x13CCA830,0xEB61BD96,0x0334FE1E,0xAA0363CF,
0xB5735C90,0x4C70A239,0xD59E9E0B,0xCBAADE14,0xEECC86BC,0x60622CA7,0x9CAB5CAB,0xB2F3846E,
0x648B1EAF,0x19BDF0CA,0xA02369B9,0x655ABB50,0x40685A32,0x3C2AB4B3,0x319EE9D5,0xC021B8F7,
0x9B540B19,0x875FA099,0x95F7997E,0x623D7DA8,0xF837889A,0x97E32D77,0x11ED935F,0x16681281,
0x0E358829,0xC7E61FD6,0x96DEDFA1,0x7858BA99,0x57F584A5,0x1B227263,0x9B83C3FF,0x1AC24696,
0xCDB30AEB,0x532E3054,0x8FD948E4,0x6DBC3128,0x58EBF2EF,0x34C6FFEA,0xFE28ED61,0xEE7C3C73,
0x5D4A14D9,0xE864B7E3,0x42105D14,0x203E13E0,0x45EEE2B6,0xA3AAABEA,0xDB6C4F15,0xFACB4FD0,
0xC742F442,0xEF6ABBB5,0x654F3B1D,0x41CD2105,0xD81E799E,0x86854DC7,0xE44B476A,0x3D816250,
0xCF62A1F2,0x5B8D2646,0xFC8883A0,0xC1C7B6A3,0x7F1524C3,0x69CB7492,0x47848A0B,0x5692B285,
0x095BBF00,0xAD19489D,0x1462B174,0x23820E00,0x58428D2A,0x0C55F5EA,0x1DADF43E,0x233F7061,
0x3372F092,0x8D937E41,0xD65FECF1,0x6C223BDB,0x7CDE3759,0xCBEE7460,0x4085F2A7,0xCE77326E,
0xA6078084,0x19F8509E,0xE8EFD855,0x61D99735,0xA969A7AA,0xC50C06C2,0x5A04ABFC,0x800BCADC,
0x9E447A2E,0xC3453484,0xFDD56705,0x0E1E9EC9,0xDB73DBD3,0x105588CD,0x675FDA79,0xE3674340,
0xC5C43465,0x713E38D8,0x3D28F89E,0xF16DFF20,0x153E21E7,0x8FB03D4A,0xE6E39F2B,0xDB83ADF7
},{
0xE93D5A68,0x948140F7,0xF64C261C,0x94692934,0x411520F7,0x7602D4F7,0xBCF46B2E,0xD4A20068,
0xD4082471,0x3320F46A,0x43B7D4B7,0x500061AF,0x1E39F62E,0x97244546,0x14214F74,0xBF8B8840,
0x4D95FC1D,0x96B591AF,0x70F4DDD3,0x66A02F45,0xBFBC09EC,0x03BD9785,0x7FAC6DD0,0x31CB8504,
0x96EB27B3,0x55FD3941,0xDA2547E6,0xABCA0A9A,0x28507825,0x530429F4,0x0A2C86DA,0xE9B66DFB,
0x68DC1462,0xD7486900,0x680EC0A4,0x27A18DEE,0x4F3FFEA2,0xE887AD8C,0xB58CE006,0x7AF4D6B6,
0xAACE1E7C,0xD3375FEC,0xCE78A399,0x406B2A42,0x20FE9E35,0xD9F385B9,0xEE39D7AB,0x3B124E8B,
0x1DC9FAF7,0x4B6D1856,0x26A36631,0xEAE397B2,0x3A6EFA74,0xDD5B4332,0x6841E7F7,0xCA7820FB,
0xFB0AF54E,0xD8FEB397,0x454056AC,0xBA489527,0x55533A3A,0x20838D87,0xFE6BA9B7,0xD096954B,
0x55A867BC,0xA1159A58,0xCCA92963,0x99E1DB33,0xA62A4A56,0x3F3125F9,0x5EF47E1C,0x9029317C,
0xFDF8E802,0x04272F70,0x80BB155C,0x05282CE3,0x95C11548,0xE4C66D22,0x48C1133F,0xC70F86DC,
0x07F9C9EE,0x41041F0F,0x404779A4,0x5D886E17,0x325F51EB,0xD59BC0D1,0xF2BCC18F,0x41113564,
0x257B7834,0x602A9C60,0xDFF8E8A3,0x1F636C1B,0x0E12B4C2,0x02E1329E,0xAF664FD1,0xCAD18115,
0x6B2395E0,0x333E92E1,0x3B240B62,0xEEBEB922,0x85B2A20E,0xE6BA0D99,0xDE720C8C,0x2DA2F728,
0xD0127845,0x95B794FD,0x647D0862,0xE7CCF5F0,0x5449A36F,0x877D48FA,0xC39DFD27,0xF33E8D1E,
0x0A476341,0x992EFF74,0x3A6F6EAB,0xF4F8FD37,0xA812DC60,0xA1EBDDF8,0x991BE14C,0xDB6E6B0D,
0xC67B5510,0x6D672C37,0x2765D43B,0xDCD0E804,0xF1290DC7,0xCC00FFA3,0xB5390F92,0x690FED0B,
0x667B9FFB,0xCEDB7D9C,0xA091CF0B,0xD9155EA3,0xBB132F88,0x515BAD24,0x7B9479BF,0x763BD6EB,
0x37392EB3,0xCC115979,0x8026E297,0xF42E312D,0x6842ADA7,0xC66A2B3B,0x12754CCC,0x782EF11C,
0x6A124237,0xB79251E7,0x06A1BBE6,0x4BFB6350,0x1A6B1018,0x11CAEDFA,0x3D25BDD8,0xE2E1C3C9,
0x44421659,0x0A121386,0xD90CEC6E,0xD5ABEA2A,0x64AF674E,0xDA86A85F,0xBEBFE988,0x64E4C3FE,
0x9DBC8057,0xF0F7C086,0x60787BF8,0x6003604D,0xD1FD8346,0xF6381FB0,0x7745AE04,0xD736FCCC,
0x83426B33,0xF01EAB71,0xB0804187,0x3C005E5F,0x77A057BE,0xBDE8AE24,0x55464299,0xBF582E61,
0x4E58F48F,0xF2DDFDA2,0xF474EF38,0x8789BDC2,0x5366F9C3,0xC8B38E74,0xB475F255,0x46FCD9B9,
0x7AEB2661,0x8B1DDF84,0x846A0E79,0x915F95E2,0x466E598E,0x20B45770,0x8CD55591,0xC902DE4C,
0xB90BACE1,0xBB8205D0,0x11A86248,0x7574A99E,0xB77F19B6,0xE0A9DC09,0x662D09A1,0xC4324633,
0xE85A1F02,0x09F0BE8C,0x4A99A025,0x1D6EFE10,0x1AB93D1D,0x0BA5A4DF,0xA186F20F,0x2868F169,
0xDCB7DA83,0x573906FE,0xA1E2CE9B,0x4FCD7F52,0x50115E01,0xA70683FA,0xA002B5C4,0x0DE6D027,
0x9AF88C27,0x773F8641,0xC3604C06,0x61A806B5,0xF0177A28,0xC0F586E0,0x006058AA,0x30DC7D62,
0x11E69ED7,0x2338EA63,0x53C2DD94,0xC2C21634,0xBBCBEE56,0x90BCB6DE,0xEBFC7DA1,0xCE591D76,
0x6F05E409,0x4B7C0188,0x39720A3D,0x7C927C24,0x86E3725F,0x724D9DB9,0x1AC15BB4,0xD39EB8FC,
0xED545578,0x08FCA5B5,0xD83D7CD3,0x4DAD0FC4,0x1E50EF5E,0xB161E6F8,0xA28514D9,0x6C51133C,
0x6FD5C7E7,0x56E14EC4,0x362ABFCE,0xDDC6C837,0xD79A3234,0x92638212,0x670EFA8E,0x406000E0
},{
0x3A39CE37,0xD3FAF5CF,0xABC27737,0x5AC52D1B,0x5CB0679E,0x4FA33742,0xD3822740,0x99BC9BBE,
0xD5118E9D,0xBF0F7315,0xD62D1C7E,0xC700C47B,0xB78C1B6B,0x21A19045,0xB26EB1BE,0x6A366EB4,
0x5748AB2F,0xBC946E79,0xC6A376D2,0x6549C2C8,0x530FF8EE,0x468DDE7D,0xD5730A1D,0x4CD04DC6,
0x2939BBDB,0xA9BA4650,0xAC9526E8,0xBE5EE304,0xA1FAD5F0,0x6A2D519A,0x63EF8CE2,0x9A86EE22,
0xC089C2B8,0x43242EF6,0xA51E03AA,0x9CF2D0A4,0x83C061BA,0x9BE96A4D,0x8FE51550,0xBA645BD6,
0x2826A2F9,0xA73A3AE1,0x4BA99586,0xEF5562E9,0xC72FEFD3,0xF752F7DA,0x3F046F69,0x77FA0A59,
0x80E4A915,0x87B08601,0x9B09E6AD,0x3B3EE593,0xE990FD5A,0x9E34D797,0x2CF0B7D9,0x022B8B51,
0x96D5AC3A,0x017DA67D,0xD1CF3ED6,0x7C7D2D28,0x1F9F25CF,0xADF2B89B,0x5AD6B472,0x5A88F54C,
0xE029AC71,0xE019A5E6,0x47B0ACFD,0xED93FA9B,0xE8D3C48D,0x283B57CC,0xF8D56629,0x79132E28,
0x785F0191,0xED756055,0xF7960E44,0xE3D35E8C,0x15056DD4,0x88F46DBA,0x03A16125,0x0564F0BD,
0xC3EB9E15,0x3C9057A2,0x97271AEC,0xA93A072A,0x1B3F6D9B,0x1E6321F5,0xF59C66FB,0x26DCF319,
0x7533D928,0xB155FDF5,0x03563482,0x8ABA3CBB,0x28517711,0xC20AD9F8,0xABCC5167,0xCCAD925F,
0x4DE81751,0x3830DC8E,0x379D5862,0x9320F991,0xEA7A90C2,0xFB3E7BCE,0x5121CE64,0x774FBE32,
0xA8B6E37E,0xC3293D46,0x48DE5369,0x6413E680,0xA2AE0810,0xDD6DB224,0x69852DFD,0x09072166,
0xB39A460A,0x6445C0DD,0x586CDECF,0x1C20C8AE,0x5BBEF7DD,0x1B588D40,0xCCD2017F,0x6BB4E3BB,
0xDDA26A7E,0x3A59FF45,0x3E350A44,0xBCB4CDD5,0x72EACEA8,0xFA6484BB,0x8D6612AE,0xBF3C6F47,
0xD29BE463,0x542F5D9E,0xAEC2771B,0xF64E6370,0x740E0D8D,0xE75B1357,0xF8721671,0xAF537D5D,
0x4040CB08,0x4EB4E2CC,0x34D2466A,0x0115AF84,0xE1B00428,0x95983A1D,0x06B89FB4,0xCE6EA048,
0x6F3F3B82,0x3520AB82,0x011A1D4B,0x277227F8,0x611560B1,0xE7933FDC,0xBB3A792B,0x344525BD,
0xA08839E1,0x51CE794B,0x2F32C9B7,0xA01FBAC9,0xE01CC87E,0xBCC7D1F6,0xCF0111C3,0xA1E8AAC7,
0x1A908749,0xD44FBD9A,0xD0DADECB,0xD50ADA38,0x0339C32A,0xC6913667,0x8DF9317C,0xE0B12B4F,
0xF79E59B7,0x43F5BB3A,0xF2D519FF,0x27D9459C,0xBF97222C,0x15E6FC2A,0x0F91FC71,0x9B941525,
0xFAE59361,0xCEB69CEB,0xC2A86459,0x12BAA8D1,0xB6C1075E,0xE3056A0C,0x10D25065,0xCB03A442,
0xE0EC6E0E,0x1698DB3B,0x4C98A0BE,0x3278E964,0x9F1F9532,0xE0D392DF,0xD3A0342B,0x8971F21E,
0x1B0A7441,0x4BA3348C,0xC5BE7120,0xC37632D8,0xDF359F8D,0x9B992F2E,0xE60B6F47,0x0FE3F11D,
0xE54CDA54,0x1EDAD891,0xCE6279CF,0xCD3E7E6F,0x1618B166,0xFD2C1D05,0x848FD2C5,0xF6FB2299,
0xF523F357,0xA6327623,0x93A83531,0x56CCCD02,0xACF08162,0x5A75EBB5,0x6E163697,0x88D273CC,
0xDE966292,0x81B949D0,0x4C50901B,0x71C65614,0xE6C6C7BD,0x327A140A,0x45E1D006,0xC3F27B9A,
0xC9AA53FD,0x62A80F00,0xBB25BFE2,0x35BDD2F6,0x71126905,0xB2040222,0xB6CBCF7C,0xCD769C2B,
0x53113EC0,0x1640E3D3,0x38ABBD60,0x2547ADF0,0xBA38209C,0xF746CE76,0x77AFA1C5,0x20756060,
0x85CBFE4E,0x8AE88DD8,0x7AAAF9B0,0x4CF9AA7E,0x1948C25C,0x02FB8A8C,0x01C36AE4,0xD6EBE1F9,
0x90D4F869,0xA65CDEA0,0x3F09252D,0xC208E69F,0xB74E6132,0xCE77E25B,0x578FDFE3,0x3AC372E6
} };
/*********************** FUNCTION DEFINITIONS ***********************/
void blowfish_encrypt(const BYTE in[], BYTE out[], const BLOWFISH_KEY *keystruct)
{
WORD l,r,t; //,i;
l = (in[0] << 24) | (in[1] << 16) | (in[2] << 8) | (in[3]);
r = (in[4] << 24) | (in[5] << 16) | (in[6] << 8) | (in[7]);
ITERATION(l,r,t,0);
ITERATION(l,r,t,1);
ITERATION(l,r,t,2);
ITERATION(l,r,t,3);
ITERATION(l,r,t,4);
ITERATION(l,r,t,5);
ITERATION(l,r,t,6);
ITERATION(l,r,t,7);
ITERATION(l,r,t,8);
ITERATION(l,r,t,9);
ITERATION(l,r,t,10);
ITERATION(l,r,t,11);
ITERATION(l,r,t,12);
ITERATION(l,r,t,13);
ITERATION(l,r,t,14);
l ^= keystruct->p[15]; F(l,t); r^= t; //Last iteration has no swap()
r ^= keystruct->p[16];
l ^= keystruct->p[17];
out[0] = l >> 24;
out[1] = l >> 16;
out[2] = l >> 8;
out[3] = l;
out[4] = r >> 24;
out[5] = r >> 16;
out[6] = r >> 8;
out[7] = r;
}
void blowfish_decrypt(const BYTE in[], BYTE out[], const BLOWFISH_KEY *keystruct)
{
WORD l,r,t; //,i;
l = (in[0] << 24) | (in[1] << 16) | (in[2] << 8) | (in[3]);
r = (in[4] << 24) | (in[5] << 16) | (in[6] << 8) | (in[7]);
ITERATION(l,r,t,17);
ITERATION(l,r,t,16);
ITERATION(l,r,t,15);
ITERATION(l,r,t,14);
ITERATION(l,r,t,13);
ITERATION(l,r,t,12);
ITERATION(l,r,t,11);
ITERATION(l,r,t,10);
ITERATION(l,r,t,9);
ITERATION(l,r,t,8);
ITERATION(l,r,t,7);
ITERATION(l,r,t,6);
ITERATION(l,r,t,5);
ITERATION(l,r,t,4);
ITERATION(l,r,t,3);
l ^= keystruct->p[2]; F(l,t); r^= t; //Last iteration has no swap()
r ^= keystruct->p[1];
l ^= keystruct->p[0];
out[0] = l >> 24;
out[1] = l >> 16;
out[2] = l >> 8;
out[3] = l;
out[4] = r >> 24;
out[5] = r >> 16;
out[6] = r >> 8;
out[7] = r;
}
void blowfish_key_setup(const BYTE user_key[], BLOWFISH_KEY *keystruct, size_t len)
{
BYTE block[8];
int idx,idx2;
// Copy over the constant init array vals (so the originals aren't destroyed).
memcpy(keystruct->p,p_perm,sizeof(WORD) * 18);
memcpy(keystruct->s,s_perm,sizeof(WORD) * 1024);
// Combine the key with the P box. Assume key is standard 448 bits (56 bytes) or less.
for (idx = 0, idx2 = 0; idx < 18; ++idx, idx2 += 4)
keystruct->p[idx] ^= (user_key[idx2 % len] << 24) | (user_key[(idx2+1) % len] << 16)
| (user_key[(idx2+2) % len] << 8) | (user_key[(idx2+3) % len]);
// Re-calculate the P box.
memset(block, 0, 8);
for (idx = 0; idx < 18; idx += 2) {
blowfish_encrypt(block,block,keystruct);
keystruct->p[idx] = (block[0] << 24) | (block[1] << 16) | (block[2] << 8) | block[3];
keystruct->p[idx+1]=(block[4] << 24) | (block[5] << 16) | (block[6] << 8) | block[7];
}
// Recalculate the S-boxes.
for (idx = 0; idx < 4; ++idx) {
for (idx2 = 0; idx2 < 256; idx2 += 2) {
blowfish_encrypt(block,block,keystruct);
keystruct->s[idx][idx2] = (block[0] << 24) | (block[1] << 16) |
(block[2] << 8) | block[3];
keystruct->s[idx][idx2+1] = (block[4] << 24) | (block[5] << 16) |
(block[6] << 8) | block[7];
}
}
}

32
blowfish.h Normal file
View File

@ -0,0 +1,32 @@
/*********************************************************************
* Filename: blowfish.h
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Defines the API for the corresponding Blowfish implementation.
*********************************************************************/
#ifndef BLOWFISH_H
#define BLOWFISH_H
/*************************** HEADER FILES ***************************/
#include <stddef.h>
/****************************** MACROS ******************************/
#define BLOWFISH_BLOCK_SIZE 8 // Blowfish operates on 8 bytes at a time
/**************************** DATA TYPES ****************************/
typedef unsigned char BYTE; // 8-bit byte
typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines
typedef struct {
WORD p[18];
WORD s[4][256];
} BLOWFISH_KEY;
/*********************** FUNCTION DECLARATIONS **********************/
void blowfish_key_setup(const BYTE user_key[], BLOWFISH_KEY *keystruct, size_t len);
void blowfish_encrypt(const BYTE in[], BYTE out[], const BLOWFISH_KEY *keystruct);
void blowfish_decrypt(const BYTE in[], BYTE out[], const BLOWFISH_KEY *keystruct);
#endif // BLOWFISH_H

68
blowfish_test.c Normal file
View File

@ -0,0 +1,68 @@
/*********************************************************************
* Filename: blowfish_test.c
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Performs known-answer tests on the corresponding Blowfish
implementation. These tests do not encompass the full
range of available test vectors, however, if the tests
pass it is very, very likely that the code is correct
and was compiled properly. This code also serves as
example usage of the functions.
*********************************************************************/
/*************************** HEADER FILES ***************************/
#include <stdio.h>
#include <memory.h>
#include "blowfish.h"
/*********************** FUNCTION DEFINITIONS ***********************/
int blowfish_test()
{
BYTE key1[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
BYTE key2[8] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
BYTE key3[24] = {0xF0,0xE1,0xD2,0xC3,0xB4,0xA5,0x96,0x87,
0x78,0x69,0x5A,0x4B,0x3C,0x2D,0x1E,0x0F,
0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77};
BYTE p1[BLOWFISH_BLOCK_SIZE] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
BYTE p2[BLOWFISH_BLOCK_SIZE] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
BYTE p3[BLOWFISH_BLOCK_SIZE] = {0xFE,0xDC,0xBA,0x98,0x76,0x54,0x32,0x10};
BYTE c1[BLOWFISH_BLOCK_SIZE] = {0x4e,0xf9,0x97,0x45,0x61,0x98,0xdd,0x78};
BYTE c2[BLOWFISH_BLOCK_SIZE] = {0x51,0x86,0x6f,0xd5,0xb8,0x5e,0xcb,0x8a};
BYTE c3[BLOWFISH_BLOCK_SIZE] = {0x05,0x04,0x4b,0x62,0xfa,0x52,0xd0,0x80};
BYTE enc_buf[BLOWFISH_BLOCK_SIZE];
BLOWFISH_KEY key;
int pass = 1;
// Test vector 1.
blowfish_key_setup(key1, &key, BLOWFISH_BLOCK_SIZE);
blowfish_encrypt(p1, enc_buf, &key);
pass = pass && !memcmp(c1, enc_buf, BLOWFISH_BLOCK_SIZE);
blowfish_decrypt(c1, enc_buf, &key);
pass = pass && !memcmp(p1, enc_buf, BLOWFISH_BLOCK_SIZE);
// Test vector 2.
blowfish_key_setup(key2, &key, BLOWFISH_BLOCK_SIZE);
blowfish_encrypt(p2, enc_buf, &key);
pass = pass && !memcmp(c2, enc_buf, BLOWFISH_BLOCK_SIZE);
blowfish_decrypt(c2, enc_buf, &key);
pass = pass && !memcmp(p2, enc_buf, BLOWFISH_BLOCK_SIZE);
// Test vector 3.
blowfish_key_setup(key3, &key, 24);
blowfish_encrypt(p3, enc_buf, &key);
pass = pass && !memcmp(c3, enc_buf, BLOWFISH_BLOCK_SIZE);
blowfish_decrypt(c3, enc_buf, &key);
pass = pass && !memcmp(p3, enc_buf, BLOWFISH_BLOCK_SIZE);
return(pass);
}
int main()
{
printf("Blowfish tests: %s\n", blowfish_test() ? "SUCCEEDED" : "FAILED");
return(0);
}

269
des.c Normal file
View File

@ -0,0 +1,269 @@
/*********************************************************************
* Filename: des.c
* Author: Brad Conte (brad AT radconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Implementation of the DES encryption algorithm.
Modes of operation (such as CBC) are not included.
The formal NIST algorithm specification can be found here:
* http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf
*********************************************************************/
/*************************** HEADER FILES ***************************/
#include <stdlib.h>
#include <memory.h>
#include "des.h"
/****************************** MACROS ******************************/
// Obtain bit "b" from the left and shift it "c" places from the right
#define BITNUM(a,b,c) (((a[(b)/8] >> (7 - (b%8))) & 0x01) << (c))
#define BITNUMINTR(a,b,c) ((((a) >> (31 - (b))) & 0x00000001) << (c))
#define BITNUMINTL(a,b,c) ((((a) << (b)) & 0x80000000) >> (c))
// This macro converts a 6 bit block with the S-Box row defined as the first and last
// bits to a 6 bit block with the row defined by the first two bits.
#define SBOXBIT(a) (((a) & 0x20) | (((a) & 0x1f) >> 1) | (((a) & 0x01) << 4))
/**************************** VARIABLES *****************************/
static const BYTE sbox1[64] = {
14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13
};
static const BYTE sbox2[64] = {
15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9
};
static const BYTE sbox3[64] = {
10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12
};
static const BYTE sbox4[64] = {
7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14
};
static const BYTE sbox5[64] = {
2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3
};
static const BYTE sbox6[64] = {
12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13
};
static const BYTE sbox7[64] = {
4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12
};
static const BYTE sbox8[64] = {
13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11
};
/*********************** FUNCTION DEFINITIONS ***********************/
// Initial (Inv)Permutation step
void IP(WORD state[], const BYTE in[])
{
state[0] = BITNUM(in,57,31) | BITNUM(in,49,30) | BITNUM(in,41,29) | BITNUM(in,33,28) |
BITNUM(in,25,27) | BITNUM(in,17,26) | BITNUM(in,9,25) | BITNUM(in,1,24) |
BITNUM(in,59,23) | BITNUM(in,51,22) | BITNUM(in,43,21) | BITNUM(in,35,20) |
BITNUM(in,27,19) | BITNUM(in,19,18) | BITNUM(in,11,17) | BITNUM(in,3,16) |
BITNUM(in,61,15) | BITNUM(in,53,14) | BITNUM(in,45,13) | BITNUM(in,37,12) |
BITNUM(in,29,11) | BITNUM(in,21,10) | BITNUM(in,13,9) | BITNUM(in,5,8) |
BITNUM(in,63,7) | BITNUM(in,55,6) | BITNUM(in,47,5) | BITNUM(in,39,4) |
BITNUM(in,31,3) | BITNUM(in,23,2) | BITNUM(in,15,1) | BITNUM(in,7,0);
state[1] = BITNUM(in,56,31) | BITNUM(in,48,30) | BITNUM(in,40,29) | BITNUM(in,32,28) |
BITNUM(in,24,27) | BITNUM(in,16,26) | BITNUM(in,8,25) | BITNUM(in,0,24) |
BITNUM(in,58,23) | BITNUM(in,50,22) | BITNUM(in,42,21) | BITNUM(in,34,20) |
BITNUM(in,26,19) | BITNUM(in,18,18) | BITNUM(in,10,17) | BITNUM(in,2,16) |
BITNUM(in,60,15) | BITNUM(in,52,14) | BITNUM(in,44,13) | BITNUM(in,36,12) |
BITNUM(in,28,11) | BITNUM(in,20,10) | BITNUM(in,12,9) | BITNUM(in,4,8) |
BITNUM(in,62,7) | BITNUM(in,54,6) | BITNUM(in,46,5) | BITNUM(in,38,4) |
BITNUM(in,30,3) | BITNUM(in,22,2) | BITNUM(in,14,1) | BITNUM(in,6,0);
}
void InvIP(WORD state[], BYTE in[])
{
in[0] = BITNUMINTR(state[1],7,7) | BITNUMINTR(state[0],7,6) | BITNUMINTR(state[1],15,5) |
BITNUMINTR(state[0],15,4) | BITNUMINTR(state[1],23,3) | BITNUMINTR(state[0],23,2) |
BITNUMINTR(state[1],31,1) | BITNUMINTR(state[0],31,0);
in[1] = BITNUMINTR(state[1],6,7) | BITNUMINTR(state[0],6,6) | BITNUMINTR(state[1],14,5) |
BITNUMINTR(state[0],14,4) | BITNUMINTR(state[1],22,3) | BITNUMINTR(state[0],22,2) |
BITNUMINTR(state[1],30,1) | BITNUMINTR(state[0],30,0);
in[2] = BITNUMINTR(state[1],5,7) | BITNUMINTR(state[0],5,6) | BITNUMINTR(state[1],13,5) |
BITNUMINTR(state[0],13,4) | BITNUMINTR(state[1],21,3) | BITNUMINTR(state[0],21,2) |
BITNUMINTR(state[1],29,1) | BITNUMINTR(state[0],29,0);
in[3] = BITNUMINTR(state[1],4,7) | BITNUMINTR(state[0],4,6) | BITNUMINTR(state[1],12,5) |
BITNUMINTR(state[0],12,4) | BITNUMINTR(state[1],20,3) | BITNUMINTR(state[0],20,2) |
BITNUMINTR(state[1],28,1) | BITNUMINTR(state[0],28,0);
in[4] = BITNUMINTR(state[1],3,7) | BITNUMINTR(state[0],3,6) | BITNUMINTR(state[1],11,5) |
BITNUMINTR(state[0],11,4) | BITNUMINTR(state[1],19,3) | BITNUMINTR(state[0],19,2) |
BITNUMINTR(state[1],27,1) | BITNUMINTR(state[0],27,0);
in[5] = BITNUMINTR(state[1],2,7) | BITNUMINTR(state[0],2,6) | BITNUMINTR(state[1],10,5) |
BITNUMINTR(state[0],10,4) | BITNUMINTR(state[1],18,3) | BITNUMINTR(state[0],18,2) |
BITNUMINTR(state[1],26,1) | BITNUMINTR(state[0],26,0);
in[6] = BITNUMINTR(state[1],1,7) | BITNUMINTR(state[0],1,6) | BITNUMINTR(state[1],9,5) |
BITNUMINTR(state[0],9,4) | BITNUMINTR(state[1],17,3) | BITNUMINTR(state[0],17,2) |
BITNUMINTR(state[1],25,1) | BITNUMINTR(state[0],25,0);
in[7] = BITNUMINTR(state[1],0,7) | BITNUMINTR(state[0],0,6) | BITNUMINTR(state[1],8,5) |
BITNUMINTR(state[0],8,4) | BITNUMINTR(state[1],16,3) | BITNUMINTR(state[0],16,2) |
BITNUMINTR(state[1],24,1) | BITNUMINTR(state[0],24,0);
}
WORD f(WORD state, const BYTE key[])
{
BYTE lrgstate[6]; //,i;
WORD t1,t2;
// Expantion Permutation
t1 = BITNUMINTL(state,31,0) | ((state & 0xf0000000) >> 1) | BITNUMINTL(state,4,5) |
BITNUMINTL(state,3,6) | ((state & 0x0f000000) >> 3) | BITNUMINTL(state,8,11) |
BITNUMINTL(state,7,12) | ((state & 0x00f00000) >> 5) | BITNUMINTL(state,12,17) |
BITNUMINTL(state,11,18) | ((state & 0x000f0000) >> 7) | BITNUMINTL(state,16,23);
t2 = BITNUMINTL(state,15,0) | ((state & 0x0000f000) << 15) | BITNUMINTL(state,20,5) |
BITNUMINTL(state,19,6) | ((state & 0x00000f00) << 13) | BITNUMINTL(state,24,11) |
BITNUMINTL(state,23,12) | ((state & 0x000000f0) << 11) | BITNUMINTL(state,28,17) |
BITNUMINTL(state,27,18) | ((state & 0x0000000f) << 9) | BITNUMINTL(state,0,23);
lrgstate[0] = (t1 >> 24) & 0x000000ff;
lrgstate[1] = (t1 >> 16) & 0x000000ff;
lrgstate[2] = (t1 >> 8) & 0x000000ff;
lrgstate[3] = (t2 >> 24) & 0x000000ff;
lrgstate[4] = (t2 >> 16) & 0x000000ff;
lrgstate[5] = (t2 >> 8) & 0x000000ff;
// Key XOR
lrgstate[0] ^= key[0];
lrgstate[1] ^= key[1];
lrgstate[2] ^= key[2];
lrgstate[3] ^= key[3];
lrgstate[4] ^= key[4];
lrgstate[5] ^= key[5];
// S-Box Permutation
state = (sbox1[SBOXBIT(lrgstate[0] >> 2)] << 28) |
(sbox2[SBOXBIT(((lrgstate[0] & 0x03) << 4) | (lrgstate[1] >> 4))] << 24) |
(sbox3[SBOXBIT(((lrgstate[1] & 0x0f) << 2) | (lrgstate[2] >> 6))] << 20) |
(sbox4[SBOXBIT(lrgstate[2] & 0x3f)] << 16) |
(sbox5[SBOXBIT(lrgstate[3] >> 2)] << 12) |
(sbox6[SBOXBIT(((lrgstate[3] & 0x03) << 4) | (lrgstate[4] >> 4))] << 8) |
(sbox7[SBOXBIT(((lrgstate[4] & 0x0f) << 2) | (lrgstate[5] >> 6))] << 4) |
sbox8[SBOXBIT(lrgstate[5] & 0x3f)];
// P-Box Permutation
state = BITNUMINTL(state,15,0) | BITNUMINTL(state,6,1) | BITNUMINTL(state,19,2) |
BITNUMINTL(state,20,3) | BITNUMINTL(state,28,4) | BITNUMINTL(state,11,5) |
BITNUMINTL(state,27,6) | BITNUMINTL(state,16,7) | BITNUMINTL(state,0,8) |
BITNUMINTL(state,14,9) | BITNUMINTL(state,22,10) | BITNUMINTL(state,25,11) |
BITNUMINTL(state,4,12) | BITNUMINTL(state,17,13) | BITNUMINTL(state,30,14) |
BITNUMINTL(state,9,15) | BITNUMINTL(state,1,16) | BITNUMINTL(state,7,17) |
BITNUMINTL(state,23,18) | BITNUMINTL(state,13,19) | BITNUMINTL(state,31,20) |
BITNUMINTL(state,26,21) | BITNUMINTL(state,2,22) | BITNUMINTL(state,8,23) |
BITNUMINTL(state,18,24) | BITNUMINTL(state,12,25) | BITNUMINTL(state,29,26) |
BITNUMINTL(state,5,27) | BITNUMINTL(state,21,28) | BITNUMINTL(state,10,29) |
BITNUMINTL(state,3,30) | BITNUMINTL(state,24,31);
// Return the final state value
return(state);
}
void des_key_setup(const BYTE key[], BYTE schedule[][6], DES_MODE mode)
{
WORD i, j, to_gen, C, D;
const WORD key_rnd_shift[16] = {1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1};
const WORD key_perm_c[28] = {56,48,40,32,24,16,8,0,57,49,41,33,25,17,
9,1,58,50,42,34,26,18,10,2,59,51,43,35};
const WORD key_perm_d[28] = {62,54,46,38,30,22,14,6,61,53,45,37,29,21,
13,5,60,52,44,36,28,20,12,4,27,19,11,3};
const WORD key_compression[48] = {13,16,10,23,0,4,2,27,14,5,20,9,
22,18,11,3,25,7,15,6,26,19,12,1,
40,51,30,36,46,54,29,39,50,44,32,47,
43,48,38,55,33,52,45,41,49,35,28,31};
// Permutated Choice #1 (copy the key in, ignoring parity bits).
for (i = 0, j = 31, C = 0; i < 28; ++i, --j)
C |= BITNUM(key,key_perm_c[i],j);
for (i = 0, j = 31, D = 0; i < 28; ++i, --j)
D |= BITNUM(key,key_perm_d[i],j);
// Generate the 16 subkeys.
for (i = 0; i < 16; ++i) {
C = ((C << key_rnd_shift[i]) | (C >> (28-key_rnd_shift[i]))) & 0xfffffff0;
D = ((D << key_rnd_shift[i]) | (D >> (28-key_rnd_shift[i]))) & 0xfffffff0;
// Decryption subkeys are reverse order of encryption subkeys so
// generate them in reverse if the key schedule is for decryption useage.
if (mode == DES_DECRYPT)
to_gen = 15 - i;
else /*(if mode == DES_ENCRYPT)*/
to_gen = i;
// Initialize the array
for (j = 0; j < 6; ++j)
schedule[to_gen][j] = 0;
for (j = 0; j < 24; ++j)
schedule[to_gen][j/8] |= BITNUMINTR(C,key_compression[j],7 - (j%8));
for ( ; j < 48; ++j)
schedule[to_gen][j/8] |= BITNUMINTR(D,key_compression[j] - 28,7 - (j%8));
}
}
void des_crypt(const BYTE in[], BYTE out[], const BYTE key[][6])
{
WORD state[2],idx,t;
IP(state,in);
for (idx=0; idx < 15; ++idx) {
t = state[1];
state[1] = f(state[1],key[idx]) ^ state[0];
state[0] = t;
}
// Perform the final loop manually as it doesn't switch sides
state[0] = f(state[1],key[15]) ^ state[0];
InvIP(state,out);
}
void three_des_key_setup(const BYTE key[], BYTE schedule[][16][6], DES_MODE mode)
{
if (mode == DES_ENCRYPT) {
des_key_setup(&key[0],schedule[0],mode);
des_key_setup(&key[8],schedule[1],!mode);
des_key_setup(&key[16],schedule[2],mode);
}
else /*if (mode == DES_DECRYPT*/ {
des_key_setup(&key[16],schedule[0],mode);
des_key_setup(&key[8],schedule[1],!mode);
des_key_setup(&key[0],schedule[2],mode);
}
}
void three_des_crypt(const BYTE in[], BYTE out[], const BYTE key[][16][6])
{
des_crypt(in,out,key[0]);
des_crypt(out,out,key[1]);
des_crypt(out,out,key[2]);
}

37
des.h Normal file
View File

@ -0,0 +1,37 @@
/*********************************************************************
* Filename: des.h
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Defines the API for the corresponding DES implementation.
Note that encryption and decryption are defined by how
the key setup is performed, the actual en/de-cryption is
performed by the same function.
*********************************************************************/
#ifndef DES_H
#define DESH
/*************************** HEADER FILES ***************************/
#include <stddef.h>
/****************************** MACROS ******************************/
#define DES_BLOCK_SIZE 8 // DES operates on 8 bytes at a time
/**************************** DATA TYPES ****************************/
typedef unsigned char BYTE; // 8-bit byte
typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines
typedef enum {
DES_ENCRYPT,
DES_DECRYPT
} DES_MODE;
/*********************** FUNCTION DECLARATIONS **********************/
void des_key_setup(const BYTE key[], BYTE schedule[][6], DES_MODE mode);
void des_crypt(const BYTE in[], BYTE out[], const BYTE key[][6]);
void three_des_key_setup(const BYTE key[], BYTE schedule[][16][6], DES_MODE mode);
void three_des_crypt(const BYTE in[], BYTE out[], const BYTE key[][16][6]);
#endif // DES_H

83
des_test.c Normal file
View File

@ -0,0 +1,83 @@
/*********************************************************************
* Filename: des_test.c
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Performs known-answer tests on the corresponding DES
implementation. These tests do not encompass the full
range of available test vectors, however, if the tests
pass it is very, very likely that the code is correct
and was compiled properly. This code also serves as
example usage of the functions.
*********************************************************************/
/*************************** HEADER FILES ***************************/
#include <stdio.h>
#include <memory.h>
#include "des.h"
/*********************** FUNCTION DEFINITIONS ***********************/
int des_test()
{
BYTE pt1[DES_BLOCK_SIZE] = {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xE7};
BYTE pt2[DES_BLOCK_SIZE] = {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF};
BYTE pt3[DES_BLOCK_SIZE] = {0x54,0x68,0x65,0x20,0x71,0x75,0x66,0x63};
BYTE ct1[DES_BLOCK_SIZE] = {0xc9,0x57,0x44,0x25,0x6a,0x5e,0xd3,0x1d};
BYTE ct2[DES_BLOCK_SIZE] = {0x85,0xe8,0x13,0x54,0x0f,0x0a,0xb4,0x05};
BYTE ct3[DES_BLOCK_SIZE] = {0xc9,0x57,0x44,0x25,0x6a,0x5e,0xd3,0x1d};
BYTE ct4[DES_BLOCK_SIZE] = {0xA8,0x26,0xFD,0x8C,0xE5,0x3B,0x85,0x5F};
BYTE key1[DES_BLOCK_SIZE] = {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF};
BYTE key2[DES_BLOCK_SIZE] = {0x13,0x34,0x57,0x79,0x9B,0xBC,0xDF,0xF1};
BYTE three_key1[DES_BLOCK_SIZE * 3] = {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF,
0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF,
0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF};
BYTE three_key2[DES_BLOCK_SIZE * 3] = {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF,
0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF,0x01,
0x45,0x67,0x89,0xAB,0xCD,0xEF,0x01,0x23};
BYTE schedule[16][6];
BYTE three_schedule[3][16][6];
BYTE buf[DES_BLOCK_SIZE];
int pass = 1;
des_key_setup(key1, schedule, DES_ENCRYPT);
des_crypt(pt1, buf, schedule);
pass = pass && !memcmp(ct1, buf, DES_BLOCK_SIZE);
des_key_setup(key1, schedule, DES_DECRYPT);
des_crypt(ct1, buf, schedule);
pass = pass && !memcmp(pt1, buf, DES_BLOCK_SIZE);
des_key_setup(key2, schedule, DES_ENCRYPT);
des_crypt(pt2, buf, schedule);
pass = pass && !memcmp(ct2, buf, DES_BLOCK_SIZE);
des_key_setup(key2, schedule, DES_DECRYPT);
des_crypt(ct2, buf, schedule);
pass = pass && !memcmp(pt2, buf, DES_BLOCK_SIZE);
three_des_key_setup(three_key1, three_schedule, DES_ENCRYPT);
three_des_crypt(pt1, buf, three_schedule);
pass = pass && !memcmp(ct3, buf, DES_BLOCK_SIZE);
three_des_key_setup(three_key1, three_schedule, DES_DECRYPT);
three_des_crypt(ct3, buf, three_schedule);
pass = pass && !memcmp(pt1, buf, DES_BLOCK_SIZE);
three_des_key_setup(three_key2, three_schedule, DES_ENCRYPT);
three_des_crypt(pt3, buf, three_schedule);
pass = pass && !memcmp(ct4, buf, DES_BLOCK_SIZE);
three_des_key_setup(three_key2, three_schedule, DES_DECRYPT);
three_des_crypt(ct4, buf, three_schedule);
pass = pass && !memcmp(pt3, buf, DES_BLOCK_SIZE);
return(pass);
}
int main()
{
printf("DES test: %s\n", des_test() ? "SUCCEEDED" : "FAILED");
return(0);
}

104
md2.c Normal file
View File

@ -0,0 +1,104 @@
/*********************************************************************
* Filename: md2.c
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Implementation of the MD2 hashing algorithm.
Algorithm specification can be found here:
* http://tools.ietf.org/html/rfc1319 .
Input is little endian byte order.
*********************************************************************/
/*************************** HEADER FILES ***************************/
#include <stdlib.h>
#include <memory.h>
#include "md2.h"
/**************************** VARIABLES *****************************/
static const BYTE s[256] = {
41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
31, 26, 219, 153, 141, 51, 159, 17, 131, 20
};
/*********************** FUNCTION DEFINITIONS ***********************/
void md2_transform(MD2_CTX *ctx, BYTE data[])
{
int j,k,t;
//memcpy(&ctx->state[16], data);
for (j=0; j < 16; ++j) {
ctx->state[j + 16] = data[j];
ctx->state[j + 32] = (ctx->state[j+16] ^ ctx->state[j]);
}
t = 0;
for (j = 0; j < 18; ++j) {
for (k = 0; k < 48; ++k) {
ctx->state[k] ^= s[t];
t = ctx->state[k];
}
t = (t+j) & 0xFF;
}
t = ctx->checksum[15];
for (j=0; j < 16; ++j) {
ctx->checksum[j] ^= s[data[j] ^ t];
t = ctx->checksum[j];
}
}
void md2_init(MD2_CTX *ctx)
{
int i;
for (i=0; i < 48; ++i)
ctx->state[i] = 0;
for (i=0; i < 16; ++i)
ctx->checksum[i] = 0;
ctx->len = 0;
}
void md2_update(MD2_CTX *ctx, const BYTE data[], size_t len)
{
size_t i;
for (i = 0; i < len; ++i) {
ctx->data[ctx->len] = data[i];
ctx->len++;
if (ctx->len == MD2_BLOCK_SIZE) {
md2_transform(ctx, ctx->data);
ctx->len = 0;
}
}
}
void md2_final(MD2_CTX *ctx, BYTE hash[])
{
int to_pad;
to_pad = MD2_BLOCK_SIZE - ctx->len;
while (ctx->len < MD2_BLOCK_SIZE)
ctx->data[ctx->len++] = to_pad;
md2_transform(ctx, ctx->data);
md2_transform(ctx, ctx->checksum);
memcpy(hash, ctx->state, MD2_BLOCK_SIZE);
}

33
md2.h Normal file
View File

@ -0,0 +1,33 @@
/*********************************************************************
* Filename: md2.h
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Defines the API for the corresponding MD2 implementation.
*********************************************************************/
#ifndef MD2_H
#define MD2_H
/*************************** HEADER FILES ***************************/
#include <stddef.h>
/****************************** MACROS ******************************/
#define MD2_BLOCK_SIZE 16
/**************************** DATA TYPES ****************************/
typedef unsigned char BYTE; // 8-bit byte
typedef struct {
BYTE data[16];
BYTE state[48];
BYTE checksum[16];
int len;
} MD2_CTX;
/*********************** FUNCTION DECLARATIONS **********************/
void md2_init(MD2_CTX *ctx);
void md2_update(MD2_CTX *ctx, const BYTE data[], size_t len);
void md2_final(MD2_CTX *ctx, BYTE hash[]); // size of hash must be MD2_BLOCK_SIZE
#endif // MD2_H

58
md2_test.c Normal file
View File

@ -0,0 +1,58 @@
/*********************************************************************
* Filename: md2_test.c
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Performs known-answer tests on the corresponding MD2
implementation. These tests do not encompass the full
range of available test vectors, however, if the tests
pass it is very, very likely that the code is correct
and was compiled properly. This code also serves as
example usage of the functions.
*********************************************************************/
/*************************** HEADER FILES ***************************/
#include <stdio.h>
#include <string.h>
#include <memory.h>
#include "md2.h"
/*********************** FUNCTION DEFINITIONS ***********************/
int md2_test()
{
BYTE text1[] = {"abc"};
BYTE text2[] = {"abcdefghijklmnopqrstuvwxyz"};
BYTE text3_1[] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"};
BYTE text3_2[] = {"fghijklmnopqrstuvwxyz0123456789"};
BYTE hash1[MD2_BLOCK_SIZE] = {0xda,0x85,0x3b,0x0d,0x3f,0x88,0xd9,0x9b,0x30,0x28,0x3a,0x69,0xe6,0xde,0xd6,0xbb};
BYTE hash2[MD2_BLOCK_SIZE] = {0x4e,0x8d,0xdf,0xf3,0x65,0x02,0x92,0xab,0x5a,0x41,0x08,0xc3,0xaa,0x47,0x94,0x0b};
BYTE hash3[MD2_BLOCK_SIZE] = {0xda,0x33,0xde,0xf2,0xa4,0x2d,0xf1,0x39,0x75,0x35,0x28,0x46,0xc3,0x03,0x38,0xcd};
BYTE buf[16];
MD2_CTX ctx;
int pass = 1;
md2_init(&ctx);
md2_update(&ctx, text1, strlen(text1));
md2_final(&ctx, buf);
pass = pass && !memcmp(hash1, buf, MD2_BLOCK_SIZE);
// Note that the MD2 object can be re-used.
md2_init(&ctx);
md2_update(&ctx, text2, strlen(text2));
md2_final(&ctx, buf);
pass = pass && !memcmp(hash2, buf, MD2_BLOCK_SIZE);
// Note that the data is added in two chunks.
md2_init(&ctx);
md2_update(&ctx, text3_1, strlen(text3_1));
md2_update(&ctx, text3_2, strlen(text3_2));
md2_final(&ctx, buf);
pass = pass && !memcmp(hash3, buf, MD2_BLOCK_SIZE);
return(pass);
}
int main()
{
printf("MD2 tests: %s\n", md2_test() ? "SUCCEEDED" : "FAILED");
}

189
md5.c Normal file
View File

@ -0,0 +1,189 @@
/*********************************************************************
* Filename: md5.c
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Implementation of the MD5 hashing algorithm.
Algorithm specification can be found here:
* http://tools.ietf.org/html/rfc1321
This implementation uses little endian byte order.
*********************************************************************/
/*************************** HEADER FILES ***************************/
#include <stdlib.h>
#include <memory.h>
#include "md5.h"
/****************************** MACROS ******************************/
#define ROTLEFT(a,b) ((a << b) | (a >> (32-b)))
#define F(x,y,z) ((x & y) | (~x & z))
#define G(x,y,z) ((x & z) | (y & ~z))
#define H(x,y,z) (x ^ y ^ z)
#define I(x,y,z) (y ^ (x | ~z))
#define FF(a,b,c,d,m,s,t) { a += F(b,c,d) + m + t; \
a = b + ROTLEFT(a,s); }
#define GG(a,b,c,d,m,s,t) { a += G(b,c,d) + m + t; \
a = b + ROTLEFT(a,s); }
#define HH(a,b,c,d,m,s,t) { a += H(b,c,d) + m + t; \
a = b + ROTLEFT(a,s); }
#define II(a,b,c,d,m,s,t) { a += I(b,c,d) + m + t; \
a = b + ROTLEFT(a,s); }
/*********************** FUNCTION DEFINITIONS ***********************/
void md5_transform(MD5_CTX *ctx, const BYTE data[])
{
WORD a, b, c, d, m[16], i, j;
// MD5 specifies big endian byte order, but this implementation assumes a little
// endian byte order CPU. Reverse all the bytes upon input, and re-reverse them
// on output (in md5_final()).
for (i = 0, j = 0; i < 16; ++i, j += 4)
m[i] = (data[j]) + (data[j + 1] << 8) + (data[j + 2] << 16) + (data[j + 3] << 24);
a = ctx->state[0];
b = ctx->state[1];
c = ctx->state[2];
d = ctx->state[3];
FF(a,b,c,d,m[0], 7,0xd76aa478);
FF(d,a,b,c,m[1], 12,0xe8c7b756);
FF(c,d,a,b,m[2], 17,0x242070db);
FF(b,c,d,a,m[3], 22,0xc1bdceee);
FF(a,b,c,d,m[4], 7,0xf57c0faf);
FF(d,a,b,c,m[5], 12,0x4787c62a);
FF(c,d,a,b,m[6], 17,0xa8304613);
FF(b,c,d,a,m[7], 22,0xfd469501);
FF(a,b,c,d,m[8], 7,0x698098d8);
FF(d,a,b,c,m[9], 12,0x8b44f7af);
FF(c,d,a,b,m[10],17,0xffff5bb1);
FF(b,c,d,a,m[11],22,0x895cd7be);
FF(a,b,c,d,m[12], 7,0x6b901122);
FF(d,a,b,c,m[13],12,0xfd987193);
FF(c,d,a,b,m[14],17,0xa679438e);
FF(b,c,d,a,m[15],22,0x49b40821);
GG(a,b,c,d,m[1], 5,0xf61e2562);
GG(d,a,b,c,m[6], 9,0xc040b340);
GG(c,d,a,b,m[11],14,0x265e5a51);
GG(b,c,d,a,m[0], 20,0xe9b6c7aa);
GG(a,b,c,d,m[5], 5,0xd62f105d);
GG(d,a,b,c,m[10], 9,0x02441453);
GG(c,d,a,b,m[15],14,0xd8a1e681);
GG(b,c,d,a,m[4], 20,0xe7d3fbc8);
GG(a,b,c,d,m[9], 5,0x21e1cde6);
GG(d,a,b,c,m[14], 9,0xc33707d6);
GG(c,d,a,b,m[3], 14,0xf4d50d87);
GG(b,c,d,a,m[8], 20,0x455a14ed);
GG(a,b,c,d,m[13], 5,0xa9e3e905);
GG(d,a,b,c,m[2], 9,0xfcefa3f8);
GG(c,d,a,b,m[7], 14,0x676f02d9);
GG(b,c,d,a,m[12],20,0x8d2a4c8a);
HH(a,b,c,d,m[5], 4,0xfffa3942);
HH(d,a,b,c,m[8], 11,0x8771f681);
HH(c,d,a,b,m[11],16,0x6d9d6122);
HH(b,c,d,a,m[14],23,0xfde5380c);
HH(a,b,c,d,m[1], 4,0xa4beea44);
HH(d,a,b,c,m[4], 11,0x4bdecfa9);
HH(c,d,a,b,m[7], 16,0xf6bb4b60);
HH(b,c,d,a,m[10],23,0xbebfbc70);
HH(a,b,c,d,m[13], 4,0x289b7ec6);
HH(d,a,b,c,m[0], 11,0xeaa127fa);
HH(c,d,a,b,m[3], 16,0xd4ef3085);
HH(b,c,d,a,m[6], 23,0x04881d05);
HH(a,b,c,d,m[9], 4,0xd9d4d039);
HH(d,a,b,c,m[12],11,0xe6db99e5);
HH(c,d,a,b,m[15],16,0x1fa27cf8);
HH(b,c,d,a,m[2], 23,0xc4ac5665);
II(a,b,c,d,m[0], 6,0xf4292244);
II(d,a,b,c,m[7], 10,0x432aff97);
II(c,d,a,b,m[14],15,0xab9423a7);
II(b,c,d,a,m[5], 21,0xfc93a039);
II(a,b,c,d,m[12], 6,0x655b59c3);
II(d,a,b,c,m[3], 10,0x8f0ccc92);
II(c,d,a,b,m[10],15,0xffeff47d);
II(b,c,d,a,m[1], 21,0x85845dd1);
II(a,b,c,d,m[8], 6,0x6fa87e4f);
II(d,a,b,c,m[15],10,0xfe2ce6e0);
II(c,d,a,b,m[6], 15,0xa3014314);
II(b,c,d,a,m[13],21,0x4e0811a1);
II(a,b,c,d,m[4], 6,0xf7537e82);
II(d,a,b,c,m[11],10,0xbd3af235);
II(c,d,a,b,m[2], 15,0x2ad7d2bb);
II(b,c,d,a,m[9], 21,0xeb86d391);
ctx->state[0] += a;
ctx->state[1] += b;
ctx->state[2] += c;
ctx->state[3] += d;
}
void md5_init(MD5_CTX *ctx)
{
ctx->datalen = 0;
ctx->bitlen = 0;
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xEFCDAB89;
ctx->state[2] = 0x98BADCFE;
ctx->state[3] = 0x10325476;
}
void md5_update(MD5_CTX *ctx, const BYTE data[], size_t len)
{
size_t i;
for (i = 0; i < len; ++i) {
ctx->data[ctx->datalen] = data[i];
ctx->datalen++;
if (ctx->datalen == 64) {
md5_transform(ctx, ctx->data);
ctx->bitlen += 512;
ctx->datalen = 0;
}
}
}
void md5_final(MD5_CTX *ctx, BYTE hash[])
{
size_t i;
i = ctx->datalen;
// Pad whatever data is left in the buffer.
if (ctx->datalen < 56) {
ctx->data[i++] = 0x80;
while (i < 56)
ctx->data[i++] = 0x00;
}
else if (ctx->datalen >= 56) {
ctx->data[i++] = 0x80;
while (i < 64)
ctx->data[i++] = 0x00;
md5_transform(ctx, ctx->data);
memset(ctx->data, 0, 56);
}
// Append to the padding the total message's length in bits and transform.
ctx->bitlen += ctx->datalen * 8;
ctx->data[56] = ctx->bitlen;
ctx->data[57] = ctx->bitlen >> 8;
ctx->data[58] = ctx->bitlen >> 16;
ctx->data[59] = ctx->bitlen >> 24;
ctx->data[60] = ctx->bitlen >> 32;
ctx->data[61] = ctx->bitlen >> 40;
ctx->data[62] = ctx->bitlen >> 48;
ctx->data[63] = ctx->bitlen >> 56;
md5_transform(ctx, ctx->data);
// Since this implementation uses little endian byte ordering and MD uses big endian,
// reverse all the bytes when copying the final state to the output hash.
for (i = 0; i < 4; ++i) {
hash[i] = (ctx->state[0] >> (i * 8)) & 0x000000ff;
hash[i + 4] = (ctx->state[1] >> (i * 8)) & 0x000000ff;
hash[i + 8] = (ctx->state[2] >> (i * 8)) & 0x000000ff;
hash[i + 12] = (ctx->state[3] >> (i * 8)) & 0x000000ff;
}
}

34
md5.h Normal file
View File

@ -0,0 +1,34 @@
/*********************************************************************
* Filename: md5.h
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Defines the API for the corresponding MD5 implementation.
*********************************************************************/
#ifndef MD5_H
#define MD5_H
/*************************** HEADER FILES ***************************/
#include <stddef.h>
/****************************** MACROS ******************************/
#define MD5_BLOCK_SIZE 16 // MD5 outputs a 16 byte digest
/**************************** DATA TYPES ****************************/
typedef unsigned char BYTE; // 8-bit byte
typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines
typedef struct {
BYTE data[64];
WORD datalen;
unsigned long long bitlen;
WORD state[4];
} MD5_CTX;
/*********************** FUNCTION DECLARATIONS **********************/
void md5_init(MD5_CTX *ctx);
void md5_update(MD5_CTX *ctx, const BYTE data[], size_t len);
void md5_final(MD5_CTX *ctx, BYTE hash[]);
#endif // MD5_H

60
md5_test.c Normal file
View File

@ -0,0 +1,60 @@
/*********************************************************************
* Filename: md5_test.c
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Performs known-answer tests on the corresponding MD5
implementation. These tests do not encompass the full
range of available test vectors, however, if the tests
pass it is very, very likely that the code is correct
and was compiled properly. This code also serves as
example usage of the functions.
*********************************************************************/
/*************************** HEADER FILES ***************************/
#include <stdio.h>
#include <memory.h>
#include <string.h>
#include "md5.h"
/*********************** FUNCTION DEFINITIONS ***********************/
int md5_test()
{
BYTE text1[] = {""};
BYTE text2[] = {"abc"};
BYTE text3_1[] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"};
BYTE text3_2[] = {"fghijklmnopqrstuvwxyz0123456789"};
BYTE hash1[MD5_BLOCK_SIZE] = {0xd4,0x1d,0x8c,0xd9,0x8f,0x00,0xb2,0x04,0xe9,0x80,0x09,0x98,0xec,0xf8,0x42,0x7e};
BYTE hash2[MD5_BLOCK_SIZE] = {0x90,0x01,0x50,0x98,0x3c,0xd2,0x4f,0xb0,0xd6,0x96,0x3f,0x7d,0x28,0xe1,0x7f,0x72};
BYTE hash3[MD5_BLOCK_SIZE] = {0xd1,0x74,0xab,0x98,0xd2,0x77,0xd9,0xf5,0xa5,0x61,0x1c,0x2c,0x9f,0x41,0x9d,0x9f};
BYTE buf[16];
MD5_CTX ctx;
int pass = 1;
md5_init(&ctx);
md5_update(&ctx, text1, strlen(text1));
md5_final(&ctx, buf);
pass = pass && !memcmp(hash1, buf, MD5_BLOCK_SIZE);
// Note the MD5 object can be reused.
md5_init(&ctx);
md5_update(&ctx, text2, strlen(text2));
md5_final(&ctx, buf);
pass = pass && !memcmp(hash2, buf, MD5_BLOCK_SIZE);
// Note the data is being added in two chunks.
md5_init(&ctx);
md5_update(&ctx, text3_1, strlen(text3_1));
md5_update(&ctx, text3_2, strlen(text3_2));
md5_final(&ctx, buf);
pass = pass && !memcmp(hash3, buf, MD5_BLOCK_SIZE);
return(pass);
}
int main()
{
printf("MD5 tests: %s\n", md5_test() ? "SUCCEEDED" : "FAILED");
return(0);
}

35
rot-13.c Normal file
View File

@ -0,0 +1,35 @@
/*********************************************************************
* Filename: rot-13.c
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Implementation of the ROT-13 encryption algorithm.
Algorithm specification can be found here:
*
This implementation uses little endian byte order.
*********************************************************************/
/*************************** HEADER FILES ***************************/
#include <string.h>
#include "rot-13.h"
/*********************** FUNCTION DEFINITIONS ***********************/
void rot13(char str[])
{
int case_type, idx, len;
for (idx = 0, len = strlen(str); idx < len; idx++) {
// Only process alphabetic characters.
if (str[idx] < 'A' || (str[idx] > 'Z' && str[idx] < 'a') || str[idx] > 'z')
continue;
// Determine if the char is upper or lower case.
if (str[idx] >= 'a')
case_type = 'a';
else
case_type = 'A';
// Rotate the char's value, ensuring it doesn't accidentally "fall off" the end.
str[idx] = (str[idx] + 13) % (case_type + 26);
if (str[idx] < 26)
str[idx] += case_type;
}
}

20
rot-13.h Normal file
View File

@ -0,0 +1,20 @@
/*********************************************************************
* Filename: rot-13.h
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Defines the API for the corresponding ROT-13 implementation.
*********************************************************************/
#ifndef ROT13_H
#define ROT13_H
/*************************** HEADER FILES ***************************/
#include <stddef.h>
/*********************** FUNCTION DECLARATIONS **********************/
// Performs IN PLACE rotation of the input. Assumes input is NULL terminated.
// Preserves each charcter's case. Ignores non alphabetic characters.
void rot13(char str[]);
#endif // ROT13_H

44
rot-13_test.c Normal file
View File

@ -0,0 +1,44 @@
/*********************************************************************
* Filename: rot-13_test.c
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Performs known-answer tests on the corresponding ROT-13
implementation. These tests do not encompass the full
range of available test vectors, however, if the tests
pass it is very, very likely that the code is correct
and was compiled properly. This code also serves as
example usage of the functions.
*********************************************************************/
/*************************** HEADER FILES ***************************/
#include <stdio.h>
#include <string.h>
#include "rot-13.h"
/*********************** FUNCTION DEFINITIONS ***********************/
int rot13_test()
{
char text[] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"};
char code[] = {"NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm"};
char buf[1024];
int pass = 1;
// To encode, just apply ROT-13.
strcpy(buf, text);
rot13(buf);
pass = pass && !strcmp(code, buf);
// To decode, just re-apply ROT-13.
rot13(buf);
pass = pass && !strcmp(text, buf);
return(pass);
}
int main()
{
printf("ROT-13 tests: %s\n", rot13_test() ? "SUCCEEDED" : "FAILED");
return(0);
}

149
sha1.c Normal file
View File

@ -0,0 +1,149 @@
/*********************************************************************
* Filename: sha1.c
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Implementation of the SHA1 hashing algorithm.
Algorithm specification can be found here:
* http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf
This implementation uses little endian byte order.
*********************************************************************/
/*************************** HEADER FILES ***************************/
#include <stdlib.h>
#include <memory.h>
#include "sha1.h"
/****************************** MACROS ******************************/
#define ROTLEFT(a, b) ((a << b) | (a >> (32 - b)))
/*********************** FUNCTION DEFINITIONS ***********************/
void sha1_transform(SHA1_CTX *ctx, const BYTE data[])
{
WORD a, b, c, d, e, i, j, t, m[80];
for (i = 0, j = 0; i < 16; ++i, j += 4)
m[i] = (data[j] << 24) + (data[j + 1] << 16) + (data[j + 2] << 8) + (data[j + 3]);
for ( ; i < 80; ++i) {
m[i] = (m[i - 3] ^ m[i - 8] ^ m[i - 14] ^ m[i - 16]);
m[i] = (m[i] << 1) | (m[i] >> 31);
}
a = ctx->state[0];
b = ctx->state[1];
c = ctx->state[2];
d = ctx->state[3];
e = ctx->state[4];
for (i = 0; i < 20; ++i) {
t = ROTLEFT(a, 5) + ((b & c) ^ (~b & d)) + e + ctx->k[0] + m[i];
e = d;
d = c;
c = ROTLEFT(b, 30);
b = a;
a = t;
}
for ( ; i < 40; ++i) {
t = ROTLEFT(a, 5) + (b ^ c ^ d) + e + ctx->k[1] + m[i];
e = d;
d = c;
c = ROTLEFT(b, 30);
b = a;
a = t;
}
for ( ; i < 60; ++i) {
t = ROTLEFT(a, 5) + ((b & c) ^ (b & d) ^ (c & d)) + e + ctx->k[2] + m[i];
e = d;
d = c;
c = ROTLEFT(b, 30);
b = a;
a = t;
}
for ( ; i < 80; ++i) {
t = ROTLEFT(a, 5) + (b ^ c ^ d) + e + ctx->k[3] + m[i];
e = d;
d = c;
c = ROTLEFT(b, 30);
b = a;
a = t;
}
ctx->state[0] += a;
ctx->state[1] += b;
ctx->state[2] += c;
ctx->state[3] += d;
ctx->state[4] += e;
}
void sha1_init(SHA1_CTX *ctx)
{
ctx->datalen = 0;
ctx->bitlen = 0;
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xEFCDAB89;
ctx->state[2] = 0x98BADCFE;
ctx->state[3] = 0x10325476;
ctx->state[4] = 0xc3d2e1f0;
ctx->k[0] = 0x5a827999;
ctx->k[1] = 0x6ed9eba1;
ctx->k[2] = 0x8f1bbcdc;
ctx->k[3] = 0xca62c1d6;
}
void sha1_update(SHA1_CTX *ctx, const BYTE data[], size_t len)
{
size_t i;
for (i = 0; i < len; ++i) {
ctx->data[ctx->datalen] = data[i];
ctx->datalen++;
if (ctx->datalen == 64) {
sha1_transform(ctx, ctx->data);
ctx->bitlen += 512;
ctx->datalen = 0;
}
}
}
void sha1_final(SHA1_CTX *ctx, BYTE hash[])
{
WORD i;
i = ctx->datalen;
// Pad whatever data is left in the buffer.
if (ctx->datalen < 56) {
ctx->data[i++] = 0x80;
while (i < 56)
ctx->data[i++] = 0x00;
}
else {
ctx->data[i++] = 0x80;
while (i < 64)
ctx->data[i++] = 0x00;
sha1_transform(ctx, ctx->data);
memset(ctx->data, 0, 56);
}
// Append to the padding the total message's length in bits and transform.
ctx->bitlen += ctx->datalen * 8;
ctx->data[63] = ctx->bitlen;
ctx->data[62] = ctx->bitlen >> 8;
ctx->data[61] = ctx->bitlen >> 16;
ctx->data[60] = ctx->bitlen >> 24;
ctx->data[59] = ctx->bitlen >> 32;
ctx->data[58] = ctx->bitlen >> 40;
ctx->data[57] = ctx->bitlen >> 48;
ctx->data[56] = ctx->bitlen >> 56;
sha1_transform(ctx, ctx->data);
// Since this implementation uses little endian byte ordering and MD uses big endian,
// reverse all the bytes when copying the final state to the output hash.
for (i = 0; i < 4; ++i) {
hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;
hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff;
hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff;
hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff;
hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff;
}
}

35
sha1.h Normal file
View File

@ -0,0 +1,35 @@
/*********************************************************************
* Filename: sha1.h
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Defines the API for the corresponding SHA1 implementation.
*********************************************************************/
#ifndef SHA1_H
#define SHA1_H
/*************************** HEADER FILES ***************************/
#include <stddef.h>
/****************************** MACROS ******************************/
#define SHA1_BLOCK_SIZE 20 // SHA1 outputs a 20 byte digest
/**************************** DATA TYPES ****************************/
typedef unsigned char BYTE; // 8-bit byte
typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines
typedef struct {
BYTE data[64];
WORD datalen;
unsigned long long bitlen;
WORD state[5];
WORD k[4];
} SHA1_CTX;
/*********************** FUNCTION DECLARATIONS **********************/
void sha1_init(SHA1_CTX *ctx);
void sha1_update(SHA1_CTX *ctx, const BYTE data[], size_t len);
void sha1_final(SHA1_CTX *ctx, BYTE hash[]);
#endif // SHA1_H

58
sha1_test.c Normal file
View File

@ -0,0 +1,58 @@
/*********************************************************************
* Filename: sha1_test.c
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Performs known-answer tests on the corresponding SHA1
implementation. These tests do not encompass the full
range of available test vectors, however, if the tests
pass it is very, very likely that the code is correct
and was compiled properly. This code also serves as
example usage of the functions.
*********************************************************************/
/*************************** HEADER FILES ***************************/
#include <stdio.h>
#include <memory.h>
#include <string.h>
#include "sha1.h"
/*********************** FUNCTION DEFINITIONS ***********************/
int sha1_test()
{
BYTE text1[] = {"abc"};
BYTE text2[] = {"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"};
BYTE text3[] = {"aaaaaaaaaa"};
BYTE hash1[SHA1_BLOCK_SIZE] = {0xa9,0x99,0x3e,0x36,0x47,0x06,0x81,0x6a,0xba,0x3e,0x25,0x71,0x78,0x50,0xc2,0x6c,0x9c,0xd0,0xd8,0x9d};
BYTE hash2[SHA1_BLOCK_SIZE] = {0x84,0x98,0x3e,0x44,0x1c,0x3b,0xd2,0x6e,0xba,0xae,0x4a,0xa1,0xf9,0x51,0x29,0xe5,0xe5,0x46,0x70,0xf1};
BYTE hash3[SHA1_BLOCK_SIZE] = {0x34,0xaa,0x97,0x3c,0xd4,0xc4,0xda,0xa4,0xf6,0x1e,0xeb,0x2b,0xdb,0xad,0x27,0x31,0x65,0x34,0x01,0x6f};
BYTE buf[SHA1_BLOCK_SIZE];
int idx;
SHA1_CTX ctx;
int pass = 1;
sha1_init(&ctx);
sha1_update(&ctx, text1, strlen(text1));
sha1_final(&ctx, buf);
pass = pass && !memcmp(hash1, buf, SHA1_BLOCK_SIZE);
sha1_init(&ctx);
sha1_update(&ctx, text2, strlen(text2));
sha1_final(&ctx, buf);
pass = pass && !memcmp(hash2, buf, SHA1_BLOCK_SIZE);
sha1_init(&ctx);
for (idx = 0; idx < 100000; ++idx)
sha1_update(&ctx, text3, strlen(text3));
sha1_final(&ctx, buf);
pass = pass && !memcmp(hash3, buf, SHA1_BLOCK_SIZE);
return(pass);
}
int main()
{
printf("SHA1 tests: %s\n", sha1_test() ? "SUCCEEDED" : "FAILED");
return(0);
}

158
sha256.c Normal file
View File

@ -0,0 +1,158 @@
/*********************************************************************
* Filename: sha256.c
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Implementation of the SHA-256 hashing algorithm.
SHA-256 is one of the three algorithms in the SHA2
specification. The others, SHA-384 and SHA-512, are not
offered in this implementation.
Algorithm specification can be found here:
* http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf
This implementation uses little endian byte order.
*********************************************************************/
/*************************** HEADER FILES ***************************/
#include <stdlib.h>
#include <memory.h>
#include "sha256.h"
/****************************** MACROS ******************************/
#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b))))
#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b))))
#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22))
#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25))
#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3))
#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10))
/**************************** VARIABLES *****************************/
static const WORD k[64] = {
0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
};
/*********************** FUNCTION DEFINITIONS ***********************/
void sha256_transform(SHA256_CTX *ctx, const BYTE data[])
{
WORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64];
for (i = 0, j = 0; i < 16; ++i, j += 4)
m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]);
for ( ; i < 64; ++i)
m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
a = ctx->state[0];
b = ctx->state[1];
c = ctx->state[2];
d = ctx->state[3];
e = ctx->state[4];
f = ctx->state[5];
g = ctx->state[6];
h = ctx->state[7];
for (i = 0; i < 64; ++i) {
t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i];
t2 = EP0(a) + MAJ(a,b,c);
h = g;
g = f;
f = e;
e = d + t1;
d = c;
c = b;
b = a;
a = t1 + t2;
}
ctx->state[0] += a;
ctx->state[1] += b;
ctx->state[2] += c;
ctx->state[3] += d;
ctx->state[4] += e;
ctx->state[5] += f;
ctx->state[6] += g;
ctx->state[7] += h;
}
void sha256_init(SHA256_CTX *ctx)
{
ctx->datalen = 0;
ctx->bitlen = 0;
ctx->state[0] = 0x6a09e667;
ctx->state[1] = 0xbb67ae85;
ctx->state[2] = 0x3c6ef372;
ctx->state[3] = 0xa54ff53a;
ctx->state[4] = 0x510e527f;
ctx->state[5] = 0x9b05688c;
ctx->state[6] = 0x1f83d9ab;
ctx->state[7] = 0x5be0cd19;
}
void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len)
{
WORD i;
for (i = 0; i < len; ++i) {
ctx->data[ctx->datalen] = data[i];
ctx->datalen++;
if (ctx->datalen == 64) {
sha256_transform(ctx, ctx->data);
ctx->bitlen += 512;
ctx->datalen = 0;
}
}
}
void sha256_final(SHA256_CTX *ctx, BYTE hash[])
{
WORD i;
i = ctx->datalen;
// Pad whatever data is left in the buffer.
if (ctx->datalen < 56) {
ctx->data[i++] = 0x80;
while (i < 56)
ctx->data[i++] = 0x00;
}
else {
ctx->data[i++] = 0x80;
while (i < 64)
ctx->data[i++] = 0x00;
sha256_transform(ctx, ctx->data);
memset(ctx->data, 0, 56);
}
// Append to the padding the total message's length in bits and transform.
ctx->bitlen += ctx->datalen * 8;
ctx->data[63] = ctx->bitlen;
ctx->data[62] = ctx->bitlen >> 8;
ctx->data[61] = ctx->bitlen >> 16;
ctx->data[60] = ctx->bitlen >> 24;
ctx->data[59] = ctx->bitlen >> 32;
ctx->data[58] = ctx->bitlen >> 40;
ctx->data[57] = ctx->bitlen >> 48;
ctx->data[56] = ctx->bitlen >> 56;
sha256_transform(ctx, ctx->data);
// Since this implementation uses little endian byte ordering and SHA uses big endian,
// reverse all the bytes when copying the final state to the output hash.
for (i = 0; i < 4; ++i) {
hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;
hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff;
hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff;
hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff;
hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff;
hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff;
hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff;
hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff;
}
}

34
sha256.h Normal file
View File

@ -0,0 +1,34 @@
/*********************************************************************
* Filename: sha256.h
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Defines the API for the corresponding SHA1 implementation.
*********************************************************************/
#ifndef SHA256_H
#define SHA256_H
/*************************** HEADER FILES ***************************/
#include <stddef.h>
/****************************** MACROS ******************************/
#define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest
/**************************** DATA TYPES ****************************/
typedef unsigned char BYTE; // 8-bit byte
typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines
typedef struct {
BYTE data[64];
WORD datalen;
unsigned long long bitlen;
WORD state[8];
} SHA256_CTX;
/*********************** FUNCTION DECLARATIONS **********************/
void sha256_init(SHA256_CTX *ctx);
void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len);
void sha256_final(SHA256_CTX *ctx, BYTE hash[]);
#endif // SHA256_H

61
sha256_test.c Normal file
View File

@ -0,0 +1,61 @@
/*********************************************************************
* Filename: sha256.c
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Performs known-answer tests on the corresponding SHA1
implementation. These tests do not encompass the full
range of available test vectors, however, if the tests
pass it is very, very likely that the code is correct
and was compiled properly. This code also serves as
example usage of the functions.
*********************************************************************/
/*************************** HEADER FILES ***************************/
#include <stdio.h>
#include <memory.h>
#include <string.h>
#include "sha256.h"
/*********************** FUNCTION DEFINITIONS ***********************/
int sha256_test()
{
BYTE text1[] = {"abc"};
BYTE text2[] = {"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"};
BYTE text3[] = {"aaaaaaaaaa"};
BYTE hash1[SHA256_BLOCK_SIZE] = {0xba,0x78,0x16,0xbf,0x8f,0x01,0xcf,0xea,0x41,0x41,0x40,0xde,0x5d,0xae,0x22,0x23,
0xb0,0x03,0x61,0xa3,0x96,0x17,0x7a,0x9c,0xb4,0x10,0xff,0x61,0xf2,0x00,0x15,0xad};
BYTE hash2[SHA256_BLOCK_SIZE] = {0x24,0x8d,0x6a,0x61,0xd2,0x06,0x38,0xb8,0xe5,0xc0,0x26,0x93,0x0c,0x3e,0x60,0x39,
0xa3,0x3c,0xe4,0x59,0x64,0xff,0x21,0x67,0xf6,0xec,0xed,0xd4,0x19,0xdb,0x06,0xc1};
BYTE hash3[SHA256_BLOCK_SIZE] = {0xcd,0xc7,0x6e,0x5c,0x99,0x14,0xfb,0x92,0x81,0xa1,0xc7,0xe2,0x84,0xd7,0x3e,0x67,
0xf1,0x80,0x9a,0x48,0xa4,0x97,0x20,0x0e,0x04,0x6d,0x39,0xcc,0xc7,0x11,0x2c,0xd0};
BYTE buf[SHA256_BLOCK_SIZE];
SHA256_CTX ctx;
int idx;
int pass = 1;
sha256_init(&ctx);
sha256_update(&ctx, text1, strlen(text1));
sha256_final(&ctx, buf);
pass = pass && !memcmp(hash1, buf, SHA256_BLOCK_SIZE);
sha256_init(&ctx);
sha256_update(&ctx, text2, strlen(text2));
sha256_final(&ctx, buf);
pass = pass && !memcmp(hash2, buf, SHA256_BLOCK_SIZE);
sha256_init(&ctx);
for (idx = 0; idx < 100000; ++idx)
sha256_update(&ctx, text3, strlen(text3));
sha256_final(&ctx, buf);
pass = pass && !memcmp(hash3, buf, SHA256_BLOCK_SIZE);
return(pass);
}
int main()
{
printf("SHA-256 tests: %s\n", sha256_test() ? "SUCCEEDED" : "FAILEd");
return(0);
}