算法描述:ftp://ebible.org/pub/public/sapphire.pdf
VS2010新建控制台空项目,加入下面的代码:
CSapphire.h:
#ifndef __CSAPPHIRE_H__
#define __CSAPPHIRE_H__
class CSapphire {
public:
CSapphire(unsigned char *key = 0, unsigned char keysize = 0); // Calls initialize if a real key is provided. If none is provided, call initialize before encrypt or decrypt.
~CSapphire(); // Destroy cipher state information.
void initialize(unsigned char *key, unsigned char keysize); // User key is used to set up state information.
void hash_init(void); // Set up default hash.
unsigned char encrypt(unsigned char b = 0); // Encrypt byte or get a random byte.
unsigned char decrypt(unsigned char b); // Decrypt byte.
void hash_final(unsigned char *hash, unsigned char hashlength = 20); // Copy hash value to hash Hash length (16-32)
void burn(void); // Destroy cipher state information.
private:
unsigned char cards[256]; // A permutation of 0-255.
unsigned char rotor, // Index that rotates smoothly
ratchet, // Index that moves erratically
avalanche, // Index heavily data dependent
last_plain, // Last plain text byte
last_cipher; // Last cipher text byte
unsigned char keyrand(int limit, unsigned char *user_key, unsigned char keysize, unsigned char *rsum, unsigned *keypos);
};
#endif
CSapphire.cpp:
#include "CSapphire.h"
#include <string.h>
unsigned char CSapphire::keyrand(int limit, unsigned char *user_key, unsigned char keysize, unsigned char *rsum, unsigned *keypos) {
unsigned u; // Value from 0 to limit to return.
unsigned retry_limiter = 0; // No infinite loops allowed.
unsigned mask = 1; // Select just enough bits.
while (mask < limit) // the desired range.
mask = (mask << 1) + 1;
do {
*rsum = cards[*rsum] + user_key[(*keypos)++];
if (*keypos >= keysize) {
*keypos = 0; // Recycle the user key.
*rsum += keysize; // key "aaaa" != key "aaaaaaaa"
}
u = mask & *rsum;
if (++retry_limiter > 11)
u %= limit; // Prevent very rare long loops.
} while (u > limit);
return u;
}
void CSapphire::initialize(unsigned char *key, unsigned char keysize) {
// Key size may be up to 256 bytes.
// Pass phrases may be used directly, with longer length
// compensating for the low entropy expected in such keys.
// Alternatively, shorter keys hashed from a pass phrase or
// generated randomly may be used. For random keys, lengths
// of from 4 to 16 bytes are recommended, depending on how
// secure you want this to be.
int i;
unsigned char toswap, swaptemp, rsum;
unsigned keypos;
// If we have been given no key, assume the default hash setup.
if (keysize < 1) {
hash_init();
return;
}
// Start with cards all in order, one of each.
for (i = 0; i < 256; i++)
cards[i] = i;
// Swap the card at each position with some other card.
toswap = 0;
keypos = 0;
rsum = 0; // Start with first byte of user key.
for (i = 255; i >= 0; i--) {
toswap = keyrand(i, key, keysize, &rsum, &keypos);
swaptemp = cards[i];
cards[i] = cards[toswap];
cards[toswap] = swaptemp;
}
// Initialize the indices and data dependencies.
// Indices are set to different values instead of all 0
// to reduce what is known about the state of the cards
// when the first byte is emitted.
rotor = cards[1];
ratchet = cards[3];
avalanche = cards[5];
last_plain = cards[7];
last_cipher = cards[rsum];
toswap = swaptemp = rsum = 0;
keypos = 0;
}
void CSapphire::hash_init(void) {
// This function is used to initialize non-keyed hash computation.
// Initialize the indices and data dependencies.
rotor = 1;
ratchet = 3;
avalanche = 5;
last_plain = 7;
last_cipher = 11;
// Start with cards all in inverse order.
for (int i = 0, j = 255; i < 256; i++, j--)
cards[i] = (unsigned char) j;
}
CSapphire::CSapphire(unsigned char *key, unsigned char keysize) {
if (key && keysize)
initialize(key, keysize);
}
void CSapphire::burn(void) {
// Destroy the key and state information in RAM.
memset(cards, 0, 256);
rotor = ratchet = avalanche = last_plain = last_cipher = 0;
}
CSapphire::~CSapphire() {
burn();
}
unsigned char CSapphire::encrypt(unsigned char b) {
// Picture a single enigma rotor with 256 positions, rewired
// on the fly by card-shuffling.
// This cipher is a variant of one invented and written
// by Michael Paul Johnson in November, 1993.
unsigned char swaptemp;
// Shuffle the deck a little more.
ratchet += cards[rotor++];
swaptemp = cards[last_cipher];
cards[last_cipher] = cards[ratchet];
cards[ratchet] = cards[last_plain];
cards[last_plain] = cards[rotor];
cards[rotor] = swaptemp;
avalanche += cards[swaptemp];
// Output one byte from the state in such a way as to make it
// very hard to figure out which one you are looking at.
last_cipher = b ^ cards[(cards[ratchet] + cards[rotor]) & 0xFF] ^ cards[cards[(cards[last_plain] + cards[last_cipher] + cards[avalanche]) & 0xFF]];
last_plain = b;
return last_cipher;
}
unsigned char CSapphire::decrypt(unsigned char b) {
unsigned char swaptemp;
// Shuffle the deck a little more.
ratchet += cards[rotor++];
swaptemp = cards[last_cipher];
cards[last_cipher] = cards[ratchet];
cards[ratchet] = cards[last_plain];
cards[last_plain] = cards[rotor];
cards[rotor] = swaptemp;
avalanche += cards[swaptemp];
// Output one byte from the state in such a way as to make it
// very hard to figure out which one you are looking at.
last_plain = b ^ cards[(cards[ratchet] + cards[rotor]) & 0xFF] ^ cards[cards[(cards[last_plain] + cards[last_cipher] + cards[avalanche]) & 0xFF]];
last_cipher = b;
return last_plain;
}
void CSapphire::hash_final(unsigned char *hash, unsigned char hashlength) {
int i;
for (i = 255; i >= 0; i--)
encrypt((unsigned char) i);
for (i = 0; i < hashlength; i++)
hash[i] = encrypt(0);
}
测试代码main.cpp:
#include "CSapphire.h"
#include <stdio.h>
#include <string.h>
int main()
{
char *pKey = "key";
char *pPlaintext = "abcdefg";
CSapphire sapphire;
char ciphertext[200]={0};
char plaintext[200]={0};
printf("plaintext = %s\n", pPlaintext);
sapphire.initialize((unsigned char*)pKey, strlen(pKey));
for (char *p=pPlaintext;*p;p++) {
char ch = sapphire.encrypt(*p);
strncat(ciphertext, &ch, sizeof(ch));
}
printf("after encrypt ciphertext = %s\n", ciphertext);
sapphire.burn();
sapphire.initialize((unsigned char*)pKey, strlen(pKey));
for (char *p=ciphertext;*p;p++) {
char ch = sapphire.decrypt(*p);
strncat(plaintext, &ch, sizeof(ch));
}
printf("after decrypt plaintext = %s\n", plaintext);
sapphire.burn();
return 0;
}