Skip to content

Instantly share code, notes, and snippets.

@jettero
Created April 16, 2009 13:17
Show Gist options
  • Save jettero/96410 to your computer and use it in GitHub Desktop.
Save jettero/96410 to your computer and use it in GitHub Desktop.
C blowfish demo
#include <openssl/blowfish.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "io.h"
#define KEYARG 1
#define SRCFILE 2
#define DSTFILE 3
#define MINARGS 2
#define MAXARGS 4
#define IV_SIZE 8 /* this is by definition, only 8 works */
#define IV_PADI 9 // we store an extra byte in here, the number of pad chars on the last block
#define BUFFER_SIZE 1024 /* this can be as big as you like, must be a multile of 8 */
#define PADI ivec[IV_SIZE]
int main(int argc, char **argv) {
BF_KEY key;
FILE *input, *output;
unsigned char ivec[IV_PADI];
char buffer[BUFFER_SIZE];
char bf_buf[BUFFER_SIZE];
int i, input_len, output_len, err;
input = stdin;
output = stdout;
if( argc < MINARGS || argc > MAXARGS ) {
user_error("usage: dec key [input_file] [output_file]\n");
return 1;
}
if( argc >= SRCFILE+1 ) {
if( !(input = fopen( argv[SRCFILE], "r" )) ) {
perror(csprintf("error while opening \"%s\" for read", argv[SRCFILE]));
exit(1);
}
if( argc >= DSTFILE+1 ) {
if( !(output = fopen( argv[DSTFILE], "w" )) ) {
perror(csprintf("error while opening \"%s\" for write", argv[DSTFILE]));
exit(1);
}
}
}
// we'll need our IV for decrypt
if( (input_len = fread(ivec, 1, IV_PADI, input)) != IV_PADI )
die(csprintf("unknown error while reading IV+PADI from input file (errono: %d)", ferror(input)));
BF_set_key(&key, strlen(argv[KEYARG]), argv[KEYARG]);
while( input_len = fread(buffer, 1, BUFFER_SIZE, input) ) {
if( input_len < BUFFER_SIZE )
if( err = ferror(input) )
die(csprintf("unknown error while reading from input file (errono: %d)", err));
BF_cbc_encrypt(buffer, bf_buf, input_len, &key, ivec, BF_DECRYPT);
/*
** BF_cbc_encrypt(const unsigned char *in, unsigned char *out,
** long length, BF_KEY *schedule, unsigned char *ivec, int enc);
**
** BF_cbc_encrypt() is the Cipher Block Chaining function for Blowfish. It
** encrypts or decrypts the 64 bits chunks of in using the key schedule,
** putting the result in out. enc decides if encryption (BF_ENCRYPT) or
** decryption (BF_DECRYPT) shall be performed. ivec must point at an 8 byte
** long initialization vector.
*/
if( feof(input) && PADI )
input_len -= PADI; // don't print the pad chars!
if( (output_len = fwrite(bf_buf, 1, input_len, output)) < input_len )
die(csprintf("unknown error while writing to output file (errono: %d)", ferror(output)));
}
if( fclose(input) ) {
perror(csprintf("error while closing \"%s\"", argv[SRCFILE]));
exit(1);
}
if( fclose(output) ) {
perror(csprintf("error while closing \"%s\"", argv[DSTFILE]));
exit(1);
}
return 0;
}
#include <openssl/blowfish.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "io.h"
#define KEYARG 1
#define SRCFILE 2
#define DSTFILE 3
#define MINARGS 2
#define MAXARGS 4
#define IV_SIZE 8 /* this is by definition, only 8 works */
#define IV_PADI 9 // we store an extra byte in here, the number of pad chars on the last block
#define BUFFER_SIZE 1024 /* this can be as big as you like, must be a multile of 8 */
#define PADI ivec[IV_SIZE]
int main(int argc, char **argv) {
BF_KEY key;
FILE *input, *output;
unsigned char ivec[IV_PADI];
char buffer[BUFFER_SIZE];
char bf_buf[BUFFER_SIZE];
int i, input_len, output_len, err;
input = stdin;
output = stdout;
if( argc < MINARGS || argc > MAXARGS ) {
user_error("usage: enc key [input_file] [output_file]\n");
return 1;
}
if( argc >= SRCFILE+1 ) {
if( !(input = fopen( argv[SRCFILE], "r" )) ) {
perror(csprintf("error while opening \"%s\" for read", argv[SRCFILE]));
exit(1);
}
if( argc >= DSTFILE+1 ) {
if( !(output = fopen( argv[DSTFILE], "w" )) ) {
perror(csprintf("error while opening \"%s\" for write", argv[DSTFILE]));
exit(1);
}
}
}
// no need for the ivec to be "cryptographically strong."
if( !RAND_pseudo_bytes(ivec, IV_SIZE) )
die(csprintf("unknown error while generating IV (error: %d)", ERR_get_error()));
PADI = '\0';
// we'll need our IV for decrypt
if( (output_len = fwrite(ivec, 1, IV_PADI, output)) != IV_PADI )
die(csprintf("unknown error while writing IV+PADI to output file (errono: %d)", ferror(output)));
BF_set_key(&key, strlen(argv[KEYARG]), argv[KEYARG]);
while( input_len = fread(buffer, 1, BUFFER_SIZE, input) ) {
if( input_len < BUFFER_SIZE )
if( err = ferror(input) )
die(csprintf("unknown error while reading from input file (errono: %d)", err));
for(i=input_len; input_len%IV_SIZE; i++) {
buffer[i] = '.';
input_len++;
PADI ++;
}
BF_cbc_encrypt(buffer, bf_buf, input_len, &key, ivec, BF_ENCRYPT);
/*
** BF_cbc_encrypt(const unsigned char *in, unsigned char *out,
** long length, BF_KEY *schedule, unsigned char *ivec, int enc);
**
** BF_cbc_encrypt() is the Cipher Block Chaining function for Blowfish. It
** encrypts or decrypts the 64 bits chunks of in using the key schedule,
** putting the result in out. enc decides if encryption (BF_ENCRYPT) or
** decryption (BF_DECRYPT) shall be performed. ivec must point at an 8 byte
** long initialization vector.
*/
if( (output_len = fwrite(bf_buf, 1, input_len, output)) < input_len )
die(csprintf("unknown error while writing to output file (errono: %d)", ferror(output)));
}
if( PADI ) {
if( fseek(output, IV_SIZE, SEEK_SET) ) {
perror(csprintf("error while closing \"%s\"", argv[SRCFILE]));
exit(1);
}
if( fwrite(ivec + IV_SIZE, 1, 1, output) != 1 )
die(csprintf("unknown error while writing PADI to output file (errono: %d)", ferror(output)));
}
if( fclose(input) ) {
perror(csprintf("error while closing \"%s\"", argv[SRCFILE]));
exit(1);
}
if( fclose(output) ) {
perror(csprintf("error while closing \"%s\"", argv[DSTFILE]));
exit(1);
}
return 0;
}
#include <stdio.h> /* fprintf */
#include <stdarg.h> /* vsnprintf */
#include <stdlib.h> /* exit, realloc */
#include "io.h"
char *csprintf_tmp = NULL;
FILE *cp = NULL;
void cleanup_csprintf() {
if( csprintf_tmp )
free(csprintf_tmp);
}
void user_error(const char *error) {
fprintf(stderr, "%s\n", error);
exit(1);
}
void __die(const char *f, int l, const char *error) {
fprintf(stderr, "[%s:%d] fatal error: %s\n", f, l, error);
exit(1);
}
void __warn(const char *f, int l, const char *error) {
fprintf(stderr, "[%s:%d] warning: %s\n", f, l, error);
}
char * csprintf(const char *fmt, ...) {
/* NOTE: I was going to to write this myself, but it was sitting right there
** in the vfprintf() manpage -- so cut-and-pasted it. */
int n, size = 100; /* Guess we need no more than 100 bytes. */
char *np;
va_list ap;
if( csprintf_tmp == NULL )
if ((csprintf_tmp = malloc(size)) == NULL)
return NULL;
while (1) {
/* Try to print in the allocated space. */
va_start(ap, fmt);
n = vsnprintf(csprintf_tmp, size, fmt, ap);
va_end(ap);
/* If that worked, return the string. */
if (n > -1 && n < size)
return csprintf_tmp;
size *= 2; /* twice the old size */
if ((np = realloc (csprintf_tmp, size)) == NULL) {
free(csprintf_tmp);
return NULL;
} else {
csprintf_tmp = np;
}
}
// we never get here
}
#ifndef __IO_H__
#define __IO_H__
#define die(X) __die(__FILE__, __LINE__, X);
#define warn(X) __warn(__FILE__, __LINE__, X);
void __die(const char *file, int parser_line, const char *error);
void __warn(const char *file, int parser_line, const char *warning);
void user_error(const char *error);
char *csprintf(const char *format, ...);
void cleanup_csprintf(); // call even if you don't use csprintf... only worth calling once, usually
#endif
SHELL=/bin/bash
key=my key
go: clean
@ make --no-print-directory `git ls-files | sed 's/$$/.ubf/'`
@ for i in *.ubf; do x=`basename $$i .ubf`; ./my_diff.pl $$x $$i; done
words.bf: enc
./enc "$(key)" $(words) $@
enc: enc.c io.o
gcc -o $@ $< -lssl io.o
dec: dec.c io.o
gcc -o $@ $< -lssl io.o
%.o: %.c %.h
gcc -o $@ -c $<
%.bf: % enc
./enc "$(key)" $< $@
%.ubf: %.bf dec
./dec "$(key)" $< $@
%.xxd: %.bf
xxd $< $@
clean:
git clean -dfx
#!/usr/bin/perl
use strict;
use Fcntl qw(:seek);
open my $orig, "<", $ARGV[0] or die $!;
open my $new, "<", $ARGV[1] or die $!;
my $s1 = -s $ARGV[0];
my $s2 = -s $ARGV[1];
my $s1x = sprintf("%07x", $s1);
my $s2x = sprintf("%07x", $s2);
if( $s1 != $s2 ) {
print "$ARGV[0] and $ARGV[1] differ in size by: ", abs($s1-$s2), " bytes\n";
exit;
}
my $diffx = 10;
my $bfs = 1024;
my ($bo, $bn, $bor);
my $pos = 0;
while( $bor = read $orig, $bo, $bfs ) {
die $! unless defined $bor;
($bor == read $new, $bn, 1024) or die $!;
for(0 .. length $bo) {
unless( substr($bo, $_, 1) eq substr($bn, $_, 1) ) {
my $xp = sprintf("%07x", $pos);
print " byte $xp of $ARGV[0] and $ARGV[1] differ\n";
$diffx--;
if( $diffx <= 0 ) {
print "that's enough ...\n";
exit 1;
}
}
$pos ++;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment