diff options
author | Dwayne C. Litzenberger <dlitz@dlitz.net> | 2009-03-01 10:00:45 -0500 |
---|---|---|
committer | Dwayne C. Litzenberger <dlitz@dlitz.net> | 2009-03-01 10:39:29 -0500 |
commit | 7f3ee6d8eb7225a53a1e63207833e2627ca8e350 (patch) | |
tree | de019329a3fdbf6c7435a11afea0e569b152572d /src/Blowfish.c | |
parent | efe206d04d175a848eaf572f58e9fd1389a3be64 (diff) | |
download | pycrypto-7f3ee6d8eb7225a53a1e63207833e2627ca8e350.tar.gz |
Add new Blowfish implementation
I wrote this implementation last year without looking at any other
implementation.
Diffstat (limited to 'src/Blowfish.c')
-rw-r--r-- | src/Blowfish.c | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/src/Blowfish.c b/src/Blowfish.c new file mode 100644 index 0000000..cfc41bb --- /dev/null +++ b/src/Blowfish.c @@ -0,0 +1,243 @@ +/* + * + * Blowfish.c : Blowfish implementation + * + * Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net> + * + * ======================================================================= + * The contents of this file are dedicated to the public domain. To the extent + * that dedication to the public domain is not available, everyone is granted a + * worldwide, perpetual, royalty-free, non-exclusive license to exercise all + * rights associated with the contents of this file for any purpose whatsoever. + * No rights are reserved. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * ======================================================================= + * + * Country of origin: Canada + * + * The Blowfish algorithm is documented at + * http://www.schneier.com/paper-blowfish-fse.html + */ + +#include <stdint.h> +#include <string.h> +#include "Python.h" + +#include "Blowfish-tables.h" + +#define MODULE_NAME Blowfish +#define BLOCK_SIZE 8 /* 64-bit block size */ +#define KEY_SIZE 0 /* variable key size */ + +#define BLOWFISH_MAGIC 0xf9d565deu +typedef struct { + uint32_t magic; + + /* P permutation */ + uint32_t P[18]; + + /* Subkeys (S-boxes) */ + uint32_t S1[256]; + uint32_t S2[256]; + uint32_t S3[256]; + uint32_t S4[256]; +} Blowfish_state; + +/* The Blowfish round function F. Everything is taken modulo 2**32 */ +#define F(a, b, c, d) (((a) + (b)) ^ (c)) + (d) + +static inline uint32_t bytes_to_word(const unsigned char *in) +{ + /* big endian */ + return (in[0] << 24) | (in[1] << 16) | (in[2] << 8) | in[3]; +} + +static inline void word_to_bytes(uint32_t w, unsigned char *out) +{ + /* big endian */ + out[0] = (w >> 24) & 0xff; + out[1] = (w >> 16) & 0xff; + out[2] = (w >> 8) & 0xff; + out[3] = w & 0xff; +} + +static inline void encrypt(Blowfish_state *self, uint32_t *pxL, uint32_t *pxR) +{ + int i; + uint32_t xL = *pxL; + uint32_t xR = *pxR; + uint32_t tmp; + + for (i = 0; i < 16; i++) { + xL ^= self->P[i]; + + /* a || b || c || d = xL (big endian) */ + xR ^= F(self->S1[(xL >> 24) & 0xff], /* S1[a] */ + self->S2[(xL >> 16) & 0xff], /* S2[b] */ + self->S3[(xL >> 8) & 0xff], /* S3[c] */ + self->S4[xL & 0xff]); /* S4[d] */ + + /* Swap xL, xR */ + tmp = xL; xL = xR; xR = tmp; + } + + /* Swap xL, xR */ + tmp = xL; xL = xR; xR = tmp; + + xR ^= self->P[16]; + xL ^= self->P[17]; + + *pxL = xL; + *pxR = xR; +} + +static inline void decrypt(Blowfish_state *self, uint32_t *pxL, uint32_t *pxR) +{ + int i; + uint32_t xL = *pxL; + uint32_t xR = *pxR; + uint32_t tmp; + + xL ^= self->P[17]; + xR ^= self->P[16]; + + /* Swap xL, xR */ + tmp = xL; xL = xR; xR = tmp; + + for (i = 15; i >= 0; i--) { + /* Swap xL, xR */ + tmp = xL; xL = xR; xR = tmp; + + /* a || b || c || d = xL (big endian) */ + xR ^= F(self->S1[(xL >> 24) & 0xff], /* S1[a] */ + self->S2[(xL >> 16) & 0xff], /* S2[b] */ + self->S3[(xL >> 8) & 0xff], /* S3[c] */ + self->S4[xL & 0xff]); /* S4[d] */ + + xL ^= self->P[i]; + } + + *pxL = xL; + *pxR = xR; +} + +void Blowfish_encrypt(Blowfish_state *self, const unsigned char *in, unsigned char *out) +{ + uint32_t xL, xR; + + /* Make sure the object is initialized */ + if (self->magic != BLOWFISH_MAGIC) { + PyErr_SetString(PyExc_AssertionError, "state not initialized"); + return; + } + + /* big endian */ + xL = bytes_to_word(in); + xR = bytes_to_word(in+4); + + encrypt(self, &xL, &xR); + + /* big endian */ + word_to_bytes(xL, out); + word_to_bytes(xR, out+4); +} + +void Blowfish_decrypt(Blowfish_state *self, const unsigned char *in, unsigned char *out) +{ + uint32_t xL, xR; + + /* Make sure the object is initialized */ + if (self->magic != BLOWFISH_MAGIC) { + PyErr_SetString(PyExc_AssertionError, "state not initialized"); + return; + } + + /* big endian */ + xL = bytes_to_word(in); + xR = bytes_to_word(in+4); + + decrypt(self, &xL, &xR); + + /* big endian */ + word_to_bytes(xL, out); + word_to_bytes(xR, out+4); +} + +void Blowfish_init(Blowfish_state *self, const unsigned char *key, int keylen) +{ + uint32_t word; + int i; + uint32_t xL, xR; + + self->magic = 0; + + if (keylen < 1) { + PyErr_SetString(PyExc_ValueError, "Key cannot be empty"); + return; + } else if (keylen > 56) { + PyErr_SetString(PyExc_ValueError, "Maximum key size is 448 bits"); + return; + } + + /* Initialize the P-array with the digits of Pi, and XOR it with the key */ + word = 0; + for (i = 0; i < 18*4; i++) { + word = (word << 8) | key[i % keylen]; + if ((i & 3) == 3) { + self->P[i >> 2] = initial_P[i >> 2] ^ word; + word = 0; + } + } + + /* Initialize the S-boxes with more digits of Pi */ + memcpy(self->S1, initial_S1, 256*sizeof(uint32_t)); + memcpy(self->S2, initial_S2, 256*sizeof(uint32_t)); + memcpy(self->S3, initial_S3, 256*sizeof(uint32_t)); + memcpy(self->S4, initial_S4, 256*sizeof(uint32_t)); + + /* Stir the subkeys */ + xL = xR = 0; + for (i = 0; i < 18; i += 2) { + encrypt(self, &xL, &xR); + self->P[i] = xL; + self->P[i+1] = xR; + } + for (i = 0; i < 256; i += 2) { + encrypt(self, &xL, &xR); + self->S1[i] = xL; + self->S1[i+1] = xR; + } + for (i = 0; i < 256; i += 2) { + encrypt(self, &xL, &xR); + self->S2[i] = xL; + self->S2[i+1] = xR; + } + for (i = 0; i < 256; i += 2) { + encrypt(self, &xL, &xR); + self->S3[i] = xL; + self->S3[i+1] = xR; + } + for (i = 0; i < 256; i += 2) { + encrypt(self, &xL, &xR); + self->S4[i] = xL; + self->S4[i+1] = xR; + } + + self->magic = BLOWFISH_MAGIC; +} + +#define block_state Blowfish_state +#define block_init Blowfish_init +#define block_encrypt Blowfish_encrypt +#define block_decrypt Blowfish_decrypt + +#include "block_template.c" + +/* vim:set ts=4 sw=4 sts=4 expandtab: */ |