算法描述: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
#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); }
#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; }