aboutsummaryrefslogtreecommitdiffstats
path: root/lib/arc.c
diff options
context:
space:
mode:
authorWilmer van der Gaast <wilmer@gaast.net>2007-10-07 21:42:37 +0100
committerWilmer van der Gaast <wilmer@gaast.net>2007-10-07 21:42:37 +0100
commita7b59252ddd85810c3b14357fd43602c800b9cb6 (patch)
treefb7cb8e34d6a7eeca617d247eb3aaf028864bd18 /lib/arc.c
parent9334cc280474ae55f67e058797e214d30251973a (diff)
Renaming RC4 to ArcFour (possible trademark issues).
Diffstat (limited to 'lib/arc.c')
-rw-r--r--lib/arc.c192
1 files changed, 192 insertions, 0 deletions
diff --git a/lib/arc.c b/lib/arc.c
new file mode 100644
index 00000000..a8e863f2
--- /dev/null
+++ b/lib/arc.c
@@ -0,0 +1,192 @@
+/***************************************************************************\
+* *
+* BitlBee - An IRC to IM gateway *
+* Simple (but secure) ArcFour implementation for safer password storage. *
+* *
+* Copyright 2006 Wilmer van der Gaast <wilmer@gaast.net> *
+* *
+* This library is free software; you can redistribute it and/or *
+* modify it under the terms of the GNU Lesser General Public *
+* License as published by the Free Software Foundation, version *
+* 2.1. *
+* *
+* This library is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+* Lesser General Public License for more details. *
+* *
+* You should have received a copy of the GNU Lesser General Public License *
+* along with this library; if not, write to the Free Software Foundation, *
+* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *
+* *
+\***************************************************************************/
+
+/*
+ This file implements ArcFour-encryption, which will mainly be used to
+ save IM passwords safely in the new XML-format. Possibly other uses will
+ come up later. It's supposed to be quite reliable (thanks to the use of a
+ 6-byte IV/seed), certainly compared to the old format. The only realistic
+ way to crack BitlBee passwords now is to use a sniffer to get your hands
+ on the user's password.
+
+ If you see that something's wrong in this implementation (I asked a
+ couple of people to look at it already, but who knows), please tell me.
+
+ The reason I picked ArcFour is because it's pretty simple but effective,
+ so it will work without adding several KBs or an extra library dependency.
+
+ (ArcFour is an RC4-compatible cipher. See for details:
+ http://www.mozilla.org/projects/security/pki/nss/draft-kaukonen-cipher-arcfour-03.txt)
+*/
+
+
+#include <glib.h>
+#include <gmodule.h>
+#include <stdlib.h>
+#include <string.h>
+#include "misc.h"
+#include "arc.h"
+
+/* Add some seed to the password, to make sure we *never* use the same key.
+ This defines how many bytes we use as a seed. */
+#define ARC_IV_LEN 6
+
+/* To defend against a "Fluhrer, Mantin and Shamir attack", it is recommended
+ to shuffle S[] just a bit more before you start to use it. This defines how
+ many bytes we'll request before we'll really use them for encryption. */
+#define ARC_CYCLES 1024
+
+struct arc_state *arc_keymaker( unsigned char *key, int kl, int cycles )
+{
+ struct arc_state *st;
+ int i, j, tmp;
+
+ st = g_malloc( sizeof( struct arc_state ) );
+ st->i = st->j = 0;
+ for( i = 0; i < 256; i ++ )
+ st->S[i] = i;
+
+ if( kl <= 0 )
+ kl = strlen( (char*) key );
+
+ for( i = j = 0; i < 256; i ++ )
+ {
+ j = ( j + st->S[i] + key[i%kl] ) & 0xff;
+ tmp = st->S[i];
+ st->S[i] = st->S[j];
+ st->S[j] = tmp;
+ }
+
+ for( i = 0; i < cycles; i ++ )
+ arc_getbyte( st );
+
+ return st;
+}
+
+/*
+ For those who don't know, ArcFour is basically an algorithm that generates
+ a stream of bytes after you give it a key. Just get a byte from it and
+ xor it with your cleartext. To decrypt, just give it the same key again
+ and start xorring.
+
+ The function above initializes the byte generator, the next function can
+ be used to get bytes from the generator (and shuffle things a bit).
+*/
+
+unsigned char arc_getbyte( struct arc_state *st )
+{
+ unsigned char tmp;
+
+ /* Unfortunately the st-> stuff doesn't really improve readability here... */
+ st->i ++;
+ st->j += st->S[st->i];
+ tmp = st->S[st->i];
+ st->S[st->i] = st->S[st->j];
+ st->S[st->j] = tmp;
+
+ return st->S[(st->S[st->i] + st->S[st->j]) & 0xff];
+}
+
+/*
+ The following two functions can be used for reliable encryption and
+ decryption. Known plaintext attacks are prevented by adding some (6,
+ by default) random bytes to the password before setting up the state
+ structures. These 6 bytes are also saved in the results, because of
+ course we'll need them in arc_decode().
+
+ Because the length of the resulting string is unknown to the caller,
+ it should pass a char**. Since the encode/decode functions allocate
+ memory for the string, make sure the char** points at a NULL-pointer
+ (or at least to something you already free()d), or you'll leak
+ memory. And of course, don't forget to free() the result when you
+ don't need it anymore.
+
+ Both functions return the number of bytes in the result string.
+*/
+
+int arc_encode( char *clear, int clear_len, unsigned char **crypt, char *password )
+{
+ struct arc_state *st;
+ unsigned char *key;
+ int key_len, i;
+
+ key_len = strlen( password ) + ARC_IV_LEN;
+ if( clear_len <= 0 )
+ clear_len = strlen( clear );
+
+ /* Prepare buffers and the key + IV */
+ *crypt = g_malloc( clear_len + ARC_IV_LEN );
+ key = g_malloc( key_len );
+ strcpy( (char*) key, password );
+
+ /* Add the salt. Save it for later (when decrypting) and, of course,
+ add it to the encryption key. */
+ random_bytes( crypt[0], ARC_IV_LEN );
+ memcpy( key + key_len - ARC_IV_LEN, crypt[0], ARC_IV_LEN );
+
+ /* Generate the initial S[] from the IVed key. */
+ st = arc_keymaker( key, key_len, ARC_CYCLES );
+ g_free( key );
+
+ for( i = 0; i < clear_len; i ++ )
+ crypt[0][i+ARC_IV_LEN] = clear[i] ^ arc_getbyte( st );
+
+ g_free( st );
+
+ return clear_len + ARC_IV_LEN;
+}
+
+int arc_decode( unsigned char *crypt, int crypt_len, char **clear, char *password )
+{
+ struct arc_state *st;
+ unsigned char *key;
+ int key_len, clear_len, i;
+
+ key_len = strlen( password ) + ARC_IV_LEN;
+ clear_len = crypt_len - ARC_IV_LEN;
+
+ if( clear_len < 0 )
+ {
+ *clear = g_strdup( "" );
+ return 0;
+ }
+
+ /* Prepare buffers and the key + IV */
+ *clear = g_malloc( clear_len + 1 );
+ key = g_malloc( key_len );
+ strcpy( (char*) key, password );
+ for( i = 0; i < ARC_IV_LEN; i ++ )
+ key[key_len-ARC_IV_LEN+i] = crypt[i];
+
+ /* Generate the initial S[] from the IVed key. */
+ st = arc_keymaker( key, key_len, ARC_CYCLES );
+ g_free( key );
+
+ for( i = 0; i < clear_len; i ++ )
+ clear[0][i] = crypt[i+ARC_IV_LEN] ^ arc_getbyte( st );
+ clear[0][i] = 0; /* Nice to have for plaintexts. */
+
+ g_free( st );
+
+ return clear_len;
+}