问题
I have been searching for a while for a crypto library that I can used on linux to implement HC-128/256 encryption for using on network traffic. Unfortunately, support for this seems rather rare. Bouncy Castle supports it for C# and Java, but I need it for C. I have the source code for the HC-128/256 algorithms, but no examples on how to actually use it.
HC-256 Wikipedia:
http://en.wikipedia.org/wiki/HC-256
HC-128 Source Code and Article:
http://www.ecrypt.eu.org/stream/hcp3.html
Any help?
回答1:
I created a CRYPTOSOCKET class for encrypted comms. It also has a public "encrypt" and "decrypt" function. The socket part really just does encrypt/decrypt and calls send/recv for you. The "socket" functionality of it can be easily stripped out.
This is C++. If you want C, just look at the encrypt and decrypt functions of the CRYPTOSOCKET class and the constructor. Its very simple. Also, this is HC-256, not HC-128.
In a header "crypto.hpp".
#include "ecrypt-sync.h"
#ifndef CRYPTO_H
#define CRYPTO_H
class CRYPTOSOCKET{
public:
/**
* Creates and initializes the structures required for encryption.
*
* @param[in] socket
* The socket to send and receive data on. This should already be connected.
* @param[in] key
* The key used for encryption and decryption.
* @param[in] iv
* The initialization vector used by AES256 CBC mode. This can just be random bytes.
*
* @see generateRandom
*/
CRYPTOSOCKET(int socket, unsigned char *key, unsigned char *iv);
~CRYPTOSOCKET();
/**
* A wrapper for sending data across the connection.
*
* This encrypts the data into an intermediate buffer
* prior to sending it across the wire.
*
* @see man send
*/
ssize_t send(const void *buf, size_t len, int flags);
/**
* A wrapper for receiving data across the connection.
*
* This receives the encrypted data into an intermediate buffer,
* then decrypts it, and writes it to the output buffer.
*
* @see man recv
*/
ssize_t recv(void *buf, size_t len, int flags);
/**
* Encrypts the specified data and places the encrypted data in the specified buffer.
*
* @param len Used as input for how long the plaintext is, then for output of how long the cipher text is.
* @param[in] plaintext The unencrypted data to encrypt.
* @param[out] ciphertext Where to place the encrypted data.
*
* @returns A pointer to the ciphertext.
*
* @see unsigned char *decrypt(unsigned char *ciphertext, unsigned int len, unsigned char *plaintext)
*/
unsigned char *encrypt(unsigned char *plaintext, unsigned int len, unsigned char *ciphertext);
/**
* Decrypts the specified data and places the unencrypted data into the specified buffer.
*
* @param len Used as input for how long the ciphertext is and as output for how long the plaintext is.
* @param[in] ciphertext The encrypted data to unencrypt.
* @param[out] plaintext The buffer to place the unencrypted data in.
*
* @returns A pointer to the plaintext.
*
* @see unsigned char *encrypt(unsigned char *plaintext, unsigned int len, unsigned char *ciphertext)
*/
unsigned char *decrypt(unsigned char *ciphertext, unsigned int len, unsigned char *plaintext);
int sock; /**< The underlying socket that this sends and receives on. */
private:
ECRYPT_ctx e_ctx; /**< The ctx used for encryption. */
ECRYPT_ctx d_ctx; /**< The ctx used for decryption. */
};
#endif
And inside "crypto.cpp":
#include "crypto.hpp"
#include <sys/types.h>
#include <sys/socket.h>
CRYPTOSOCKET::CRYPTOSOCKET(int socket, unsigned char *key, unsigned char *iv){
// Initialize the encryptor.
ECRYPT_keysetup(&e_ctx, key, 128, 128);
ECRYPT_ivsetup(&e_ctx, iv);
// Initialize the decryptor.
ECRYPT_keysetup(&d_ctx, key, 128, 128);
ECRYPT_ivsetup(&d_ctx, iv);
sock = socket;
};
CRYPTOSOCKET::~CRYPTOSOCKET(){
// Nothing to do.
};
unsigned char *CRYPTOSOCKET::encrypt(unsigned char *plaintext, unsigned int len, unsigned char *ciphertext){
ECRYPT_process_bytes(0, &e_ctx, plaintext, ciphertext, len);
return ciphertext;
}
unsigned char *CRYPTOSOCKET::decrypt(unsigned char *ciphertext, unsigned int len, unsigned char *plaintext){
ECRYPT_process_bytes(1, &d_ctx, ciphertext, plaintext, len);
return plaintext;
}
ssize_t CRYPTOSOCKET::send(const void *buf, size_t len, int flags){
unsigned char buffer[len];
encrypt((unsigned char*)buf, len, buffer);
return ::send(sock, buffer, len, MSG_WAITALL);
};
ssize_t CRYPTOSOCKET::recv(void *buf, size_t len, int flags){
unsigned char buffer[len];
int data = ::recv(sock, buffer, len, MSG_WAITALL);
if(data > 0)
decrypt(buffer, len, (unsigned char *)buf);
return data;
};
/*******************************************************************
* ECRYPT crap below here....
*/
/* ecrypt-sync.c */
/* *** Please do not edit below here. *** */
//#include "ecrypt-sync.h"
void ECRYPT_init(void){
};
void ECRYPT_process_bytes(
int action, /* 0 = encrypt; 1 = decrypt; */
ECRYPT_ctx* ctx,
const u8* input,
u8* output,
u32 msglen) /* Message length in bytes. */
{
u32 i, j, msglen32, keystreamword;
msglen32 = msglen >> 2;
for (i = 0; i < msglen32; i++) {
keystreamword = generate(ctx); /*generate a 32-bit word*/
for (j = 0; j < 4; j++) {
*output = *input ^ keystreamword; /*encrypt one byte*/
output += 1;
input +=1;
keystreamword = keystreamword >> 8;
}
}
keystreamword = generate(ctx);
for (i = 0; i < (msglen & 3); i++) {
*output = *input ^ keystreamword; /*encrypt one byte*/
output += 1;
input +=1;
keystreamword = keystreamword >> 8;
}
}
void ECRYPT_ivsetup(
ECRYPT_ctx* ctx,
const u8* iv)
{
u32 W[2560],i;
/* initialize the iv */
for (i = 0; i < 8; i++) ctx->iv[i] = 0;
for (i = 0; (i < ctx->ivsize) & (i < 32); i++) {
ctx->iv[i >> 2] = ctx->iv[i >> 2] | iv[i];
ctx->iv[i >> 2] = ROTL32(ctx->iv[i >> 2],8);
}
/* setup the table P and Q */
for (i = 0; i < 8; i++) W[i] = ctx->key[i];
for (i = 8; i < 16; i++) W[i] = ctx->iv[i-8];
for (i = 16; i < 2560; i++) W[i] = f2(W[i-2]) + W[i-7] + f1(W[i-15]) + W[i-16]+i;
for (i = 0; i < 1024; i++) ctx->P[i] = W[i+512];
for (i = 0; i < 1024; i++) ctx->Q[i] = W[i+1536];
ctx->counter2048 = 0;
/* run the cipher 4096 steps before generating the output */
for (i = 0; i < 4096; i++) generate(ctx);
}
void ECRYPT_keysetup(
ECRYPT_ctx* ctx,
const u8* key,
u32 keysize, /* Key size in bits. */
u32 ivsize) /* IV size in bits. */
{
u32 i;
ctx->keysize = keysize >> 3;
ctx->ivsize = ivsize >> 3;
for (i = 0; i < 8; i++) ctx->key[i] = 0;
for (i = 0; (i < ctx->keysize) & (i < 32); i++) {
ctx->key[i >> 2] = ctx->key[i >> 2] | key[i];
ctx->key[i >> 2] = ROTL32(ctx->key[i >> 2],8);
}
} /* initialize the key, save the iv size*/
u32 generate(ECRYPT_ctx* ctx) /*one step of the cipher*/
{
u32 i,i3, i10, i12, i1023;
u32 output;
i = ctx->counter2048 & 0x3ff;
i3 = (i - 3) & 0x3ff;
i10 = (i - 10) & 0x3ff;
i12 = (i - 12) & 0x3ff;
i1023 = (i - 1023) & 0x3ff;
if (ctx->counter2048 < 1024) {
ctx->P[i] = ctx->P[i] + ctx->P[i10] + (ROTR32(ctx->P[i3],10)^ROTR32(ctx->P[i1023],23))+ctx->Q[(ctx->P[i3]^ctx->P[i1023])&0x3ff];
output = h1(ctx,ctx->P[i12]) ^ ctx->P[i];
}
else {
ctx->Q[i] = ctx->Q[i] + ctx->Q[i10] + (ROTR32(ctx->Q[i3],10)^ROTR32(ctx->Q[i1023],23))+ctx->P[(ctx->Q[i3]^ctx->Q[i1023])&0x3ff];
output = h2(ctx, ctx->Q[i12]) ^ ctx->Q[i];
}
ctx->counter2048 = (ctx->counter2048+1) & 0x7ff;
return (output);
}
u32 h2(ECRYPT_ctx* ctx, u32 u) {
u32 tem;
unsigned char a,b,c,d;
a = (unsigned char) ((u));
b = (unsigned char) ((u) >> 8);
c = (unsigned char) ((u) >> 16);
d = (unsigned char) ((u) >> 24);
tem = ctx->P[a]+ctx->P[256+b]+ctx->P[512+c]+ctx->P[768+d];
return (tem);
}
u32 h1(ECRYPT_ctx* ctx, u32 u) {
u32 tem;
unsigned char a,b,c,d;
a = (unsigned char) ((u));
b = (unsigned char) ((u) >> 8);
c = (unsigned char) ((u) >> 16);
d = (unsigned char) ((u) >> 24);
tem = ctx->Q[a]+ctx->Q[256+b]+ctx->Q[512+c]+ctx->Q[768+d];
return (tem);
}
#ifdef ECRYPT_USES_DEFAULT_ALL_IN_ONE
/*
* Default implementation of all-in-one encryption/decryption of
* (short) packets.
*/
#ifdef ECRYPT_HAS_SINGLE_PACKET_FUNCTION
void ECRYPT_process_packet(
int action,
ECRYPT_ctx* ctx,
const u8* iv,
const u8* input,
u8* output,
u32 msglen)
{
ECRYPT_ivsetup(ctx, iv);
#ifdef ECRYPT_HAS_SINGLE_BYTE_FUNCTION
ECRYPT_process_bytes(action, ctx, input, output, msglen);
#else
if (action == 0)
ECRYPT_encrypt_bytes(ctx, input, output, msglen);
else
ECRYPT_decrypt_bytes(ctx, input, output, msglen);
#endif
}
#else
void ECRYPT_encrypt_packet(
ECRYPT_ctx* ctx,
const u8* iv,
const u8* plaintext,
u8* ciphertext,
u32 msglen)
{
ECRYPT_ivsetup(ctx, iv);
ECRYPT_encrypt_bytes(ctx, plaintext, ciphertext, msglen);
}
void ECRYPT_decrypt_packet(
ECRYPT_ctx* ctx,
const u8* iv,
const u8* ciphertext,
u8* plaintext,
u32 msglen)
{
ECRYPT_ivsetup(ctx, iv);
ECRYPT_decrypt_bytes(ctx, ciphertext, plaintext, msglen);
}
#endif
#endif
And inside "ecrypt-sync.h":
/* ecrypt-sync.h */
/*
* Header file for synchronous stream ciphers without authentication
* mechanism.
*
* *** Please only edit parts marked with "[edit]". ***
*/
#include "ecrypt-portable.h"
#ifndef ECRYPT_SYNC
#define ECRYPT_SYNC
/* ------------------------------------------------------------------------- */
/* Cipher parameters */
/*
* The name of your cipher.
*/
#define ECRYPT_NAME "ECRYPT Stream Cipher HC-256" /* [edit] */
/*
* Specify which key and IV sizes are supported by your cipher. A user
* should be able to enumerate the supported sizes by running the
* following code:
*
* for (i = 0; ECRYPT_KEYSIZE(i) <= ECRYPT_MAXKEYSIZE; ++i)
* {
* keysize = ECRYPT_KEYSIZE(i);
*
* ...
* }
*
* All sizes are in bits.
*/
#define ECRYPT_MAXKEYSIZE 256 /* [edit] */
#define ECRYPT_KEYSIZE(i) (128 + (i)*32) /* [edit] */
#define ECRYPT_MAXIVSIZE 256 /* [edit] */
#define ECRYPT_IVSIZE(i) (64 + (i)*64) /* [edit] */
/* ------------------------------------------------------------------------- */
/* Data structures */
/*
* ECRYPT_ctx is the structure containing the representation of the
* internal state of your cipher.
*/
typedef struct
{
/*
* [edit]
*
* Put here all state variable needed during the encryption process.
*/
u32 P[1024];
u32 Q[1024];
u32 counter2048;
u32 key[8];
u32 iv[8];
u32 keysize; /* key size in bytes */
u32 ivsize; /* iv size in bytes */
} ECRYPT_ctx;
/* ------------------------------------------------------------------------- */
/* Mandatory functions */
/*
* Key and message independent initialization. This function will be
* called once when the program starts (e.g., to build expanded S-box
* tables).
*/
void ECRYPT_init(void);
/*
* Key setup. It is the user's responsibility to select the values of
* keysize and ivsize from the set of supported values specified
* above.
*/
void ECRYPT_keysetup(
ECRYPT_ctx* ctx,
const u8* key,
u32 keysize, /* Key size in bits. */
u32 ivsize); /* IV size in bits. */
/*
* IV setup. After having called ECRYPT_keysetup(), the user is
* allowed to call ECRYPT_ivsetup() different times in order to
* encrypt/decrypt different messages with the same key but different
* IV's.
*/
void ECRYPT_ivsetup(
ECRYPT_ctx* ctx,
const u8* iv);
/*
* Encryption/decryption of arbitrary length messages.
*
* For efficiency reasons, the API provides two types of
* encrypt/decrypt functions. The ECRYPT_encrypt_bytes() function
* (declared here) encrypts byte strings of arbitrary length, while
* the ECRYPT_encrypt_blocks() function (defined later) only accepts
* lengths which are multiples of ECRYPT_BLOCKLENGTH.
*
* The user is allowed to make multiple calls to
* ECRYPT_encrypt_blocks() to incrementally encrypt a long message,
* but he is NOT allowed to make additional encryption calls once he
* has called ECRYPT_encrypt_bytes() (unless he starts a new message
* of course). For example, this sequence of calls is acceptable:
*
* ECRYPT_keysetup();
*
* ECRYPT_ivsetup();
* ECRYPT_encrypt_blocks();
* ECRYPT_encrypt_blocks();
* ECRYPT_encrypt_bytes();
*
* ECRYPT_ivsetup();
* ECRYPT_encrypt_blocks();
* ECRYPT_encrypt_blocks();
*
* ECRYPT_ivsetup();
* ECRYPT_encrypt_bytes();
*
* The following sequence is not:
*
* ECRYPT_keysetup();
* ECRYPT_ivsetup();
* ECRYPT_encrypt_blocks();
* ECRYPT_encrypt_bytes();
* ECRYPT_encrypt_blocks();
*/
/*
* By default ECRYPT_encrypt_bytes() and ECRYPT_decrypt_bytes() are
* defined as macros which redirect the call to a single function
* ECRYPT_process_bytes(). If you want to provide separate encryption
* and decryption functions, please undef
* ECRYPT_HAS_SINGLE_BYTE_FUNCTION.
*/
#define ECRYPT_HAS_SINGLE_BYTE_FUNCTION 1 /* [edit] */
#ifdef ECRYPT_HAS_SINGLE_BYTE_FUNCTION
#define ECRYPT_encrypt_bytes(ctx, plaintext, ciphertext, msglen) \
ECRYPT_process_bytes(0, ctx, plaintext, ciphertext, msglen)
#define ECRYPT_decrypt_bytes(ctx, ciphertext, plaintext, msglen) \
ECRYPT_process_bytes(1, ctx, ciphertext, plaintext, msglen)
void ECRYPT_process_bytes(
int action, /* 0 = encrypt; 1 = decrypt; */
ECRYPT_ctx* ctx,
const u8* input,
u8* output,
u32 msglen); /* Message length in bytes. */
#else
void ECRYPT_encrypt_bytes(
ECRYPT_ctx* ctx,
const u8* plaintext,
u8* ciphertext,
u32 msglen); /* Message length in bytes. */
void ECRYPT_decrypt_bytes(
ECRYPT_ctx* ctx,
const u8* ciphertext,
u8* plaintext,
u32 msglen); /* Message length in bytes. */
#endif
/* ------------------------------------------------------------------------- */
/* Optional features */
/*
* For testing purposes it can sometimes be useful to have a function
* which immediately generates keystream without having to provide it
* with a zero plaintext. If your cipher cannot provide this function
* (e.g., because it is not strictly a synchronous cipher), please
* reset the ECRYPT_GENERATES_KEYSTREAM flag.
*/
#define ECRYPT_GENERATES_KEYSTREAM
#ifdef ECRYPT_GENERATES_KEYSTREAM
void ECRYPT_keystream_bytes(
ECRYPT_ctx* ctx,
u8* keystream,
u32 length); /* Length of keystream in bytes. */
#endif
/* ------------------------------------------------------------------------- */
/* Optional optimizations */
/*
* By default, the functions in this section are implemented using
* calls to functions declared above. However, you might want to
* implement them differently for performance reasons.
*/
/*
* All-in-one encryption/decryption of (short) packets.
*
* The default definitions of these functions can be found in
* "ecrypt-sync.c". If you want to implement them differently, please
* undef the ECRYPT_USES_DEFAULT_ALL_IN_ONE flag.
*/
#define ECRYPT_USES_DEFAULT_ALL_IN_ONE /* [edit] */
/*
* Undef ECRYPT_HAS_SINGLE_PACKET_FUNCTION if you want to provide
* separate packet encryption and decryption functions.
*/
#define ECRYPT_HAS_SINGLE_PACKET_FUNCTION /* [edit] */
#ifdef ECRYPT_HAS_SINGLE_PACKET_FUNCTION
#define ECRYPT_encrypt_packet( \
ctx, iv, plaintext, ciphertext, mglen) \
ECRYPT_process_packet(0, \
ctx, iv, plaintext, ciphertext, mglen)
#define ECRYPT_decrypt_packet( \
ctx, iv, ciphertext, plaintext, mglen) \
ECRYPT_process_packet(1, \
ctx, iv, ciphertext, plaintext, mglen)
void ECRYPT_process_packet(
int action, /* 0 = encrypt; 1 = decrypt; */
ECRYPT_ctx* ctx,
const u8* iv,
const u8* input,
u8* output,
u32 msglen);
#else
void ECRYPT_encrypt_packet(
ECRYPT_ctx* ctx,
const u8* iv,
const u8* plaintext,
u8* ciphertext,
u32 msglen);
void ECRYPT_decrypt_packet(
ECRYPT_ctx* ctx,
const u8* iv,
const u8* ciphertext,
u8* plaintext,
u32 msglen);
#endif
/*
* Encryption/decryption of blocks.
*
* By default, these functions are defined as macros. If you want to
* provide a different implementation, please undef the
* ECRYPT_USES_DEFAULT_BLOCK_MACROS flag and implement the functions
* declared below.
*/
#define ECRYPT_BLOCKLENGTH 4 /* [edit] */
#define ECRYPT_USES_DEFAULT_BLOCK_MACROS /* [edit] */
#ifdef ECRYPT_USES_DEFAULT_BLOCK_MACROS
#define ECRYPT_encrypt_blocks(ctx, plaintext, ciphertext, blocks) \
ECRYPT_encrypt_bytes(ctx, plaintext, ciphertext, \
(blocks) * ECRYPT_BLOCKLENGTH)
#define ECRYPT_decrypt_blocks(ctx, ciphertext, plaintext, blocks) \
ECRYPT_decrypt_bytes(ctx, ciphertext, plaintext, \
(blocks) * ECRYPT_BLOCKLENGTH)
#ifdef ECRYPT_GENERATES_KEYSTREAM
#define ECRYPT_keystream_blocks(ctx, keystream, blocks) \
ECRYPT_keystream_bytes(ctx, keystream, \
(blocks) * ECRYPT_BLOCKLENGTH)
#endif
#else
/*
* Undef ECRYPT_HAS_SINGLE_BLOCK_FUNCTION if you want to provide
* separate block encryption and decryption functions.
*/
#define ECRYPT_HAS_SINGLE_BLOCK_FUNCTION /* [edit] */
#ifdef ECRYPT_HAS_SINGLE_BLOCK_FUNCTION
#define ECRYPT_encrypt_blocks(ctx, plaintext, ciphertext, blocks) \
ECRYPT_process_blocks(0, ctx, plaintext, ciphertext, blocks)
#define ECRYPT_decrypt_blocks(ctx, ciphertext, plaintext, blocks) \
ECRYPT_process_blocks(1, ctx, ciphertext, plaintext, blocks)
void ECRYPT_process_blocks(
int action, /* 0 = encrypt; 1 = decrypt; */
ECRYPT_ctx* ctx,
const u8* input,
u8* output,
u32 blocks); /* Message length in blocks. */
#else
void ECRYPT_encrypt_blocks(
ECRYPT_ctx* ctx,
const u8* plaintext,
u8* ciphertext,
u32 blocks); /* Message length in blocks. */
void ECRYPT_decrypt_blocks(
ECRYPT_ctx* ctx,
const u8* ciphertext,
u8* plaintext,
u32 blocks); /* Message length in blocks. */
#endif
#ifdef ECRYPT_GENERATES_KEYSTREAM
void ECRYPT_keystream_blocks(
ECRYPT_ctx* ctx,
u8* keystream,
u32 blocks); /* Keystream length in blocks. */
#endif
#endif
/*
* If your cipher can be implemented in different ways, you can use
* the ECRYPT_VARIANT parameter to allow the user to choose between
* them at compile time (e.g., gcc -DECRYPT_VARIANT=3 ...). Please
* only use this possibility if you really think it could make a
* significant difference and keep the number of variants
* (ECRYPT_MAXVARIANT) as small as possible (definitely not more than
* 10). Note also that all variants should have exactly the same
* external interface (i.e., the same ECRYPT_BLOCKLENGTH, etc.).
*/
#define ECRYPT_MAXVARIANT 1 /* [edit] */
#ifndef ECRYPT_VARIANT
#define ECRYPT_VARIANT 1
#endif
#if (ECRYPT_VARIANT > ECRYPT_MAXVARIANT)
#error this variant does not exist
#endif
/* ------------------------------------------------------------------------- */
#endif
/* ===========================================================================
Added functions: HC-256 Mandatory functions
============================================================================== */
#define f1(x) (ROTR32((x),7) ^ ROTR32((x),18) ^ ((x) >> 3))
#define f2(x) (ROTR32((x),17) ^ ROTR32((x),19) ^ ((x) >> 10))
/*
void ECRYPT_keysetup(
ECRYPT_ctx* ctx,
const u8* key,
u32 keysize, // Key size in bits.
u32 ivsize); // IV size in bits.
void ECRYPT_ivsetup(
ECRYPT_ctx* ctx,
const u8* iv);
void ECRYPT_process_bytes(
int action, // 0 = encrypt; 1 = decrypt;
ECRYPT_ctx* ctx,
const u8* input,
u8* output,
u32 msglen); // Message length in bytes.
*/
void ECRYPT_init(void);
u32 h1(ECRYPT_ctx* ctx, u32 u);
u32 h2(ECRYPT_ctx* ctx, u32 u);
u32 generate(ECRYPT_ctx* ctx);
Then use "ecrypt-machine.h", "ecrypt-config.h", and "ecrypt-portable.h" from here: http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc256_p3source.zip
Here is a quick application to test it. You will have to create the "generateRandom" function, or just make up some random bytes lol.
#include "crypto.hpp"
int main(int argc, char **argv){
CRYPTOSOCKET *socket;
unsigned char key[32];
unsigned char iv[32];
unsigned char buf1[1024];
unsigned char buf2[1024];
unsigned char buf3[1024];
char *teststring = "This is a test.\n";
// Generate a random key
generateRandom(key, 32);
// Generate a random IV
generateRandom(iv, 32);
// Create a new cryptosocket with that key and iv.
socket = new CRYPTOSOCKET(0, key, iv);
// Copy teststring into buffer 1
sprintf((char*)buf1,teststring);
// Encrypt buffer 1 and placed the encrypted contents into buffer 2.
socket->encrypt(buf1,strlen(teststring), buf2);
// Decrypt buffer 2 into buffer 3.
socket->decrypt(buf2, strlen(teststring), buf3);
// Print out whats in buffer 3.
printf((char*)buf3);
}
来源:https://stackoverflow.com/questions/7227908/c-crypto-libraries-supporting-hc-128-256