summaryrefslogtreecommitdiff
path: root/src/Blowfish.c
diff options
context:
space:
mode:
authorDwayne C. Litzenberger <dlitz@dlitz.net>2009-03-01 10:00:45 -0500
committerDwayne C. Litzenberger <dlitz@dlitz.net>2009-03-01 10:39:29 -0500
commit7f3ee6d8eb7225a53a1e63207833e2627ca8e350 (patch)
treede019329a3fdbf6c7435a11afea0e569b152572d /src/Blowfish.c
parentefe206d04d175a848eaf572f58e9fd1389a3be64 (diff)
downloadpycrypto-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.c243
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: */