Click here to Skip to main content
15,881,172 members
Articles / Programming Languages / C

Secure Encryption For Data Storage with Key Re-use

Rate me:
Please Sign up or sign in to vote.
2.83/5 (4 votes)
22 Jul 2008CPOL2 min read 24.6K   348   8   2
Enhanced encryption algorthim for data storage (console app)

Introduction

Many single file encryption algorithms use a simple stream cipher. These ciphers XOR the bytes in the file to be encrypted with a series of outputs from a pseudo-random number generator (PRNG). If the user encrypts the same file twice using the same key, the exact same encrypted output will be generated.

If a cryptanalyst thinks that a user has used the same key to encrypt two different files, he can XOR the two files together and cancel out the output from the PRNG. This leaves the cryptanalyst with a file that contains only the two original files XORed against each other. Guessing at the original contents becomes much easier in this case.

Additionally, the cryptanalyst can use plain text attacks. In these attacks, if the cryptanalyst knows the file type, then he can use knowledge of header formats to guess at the key stream used to encode the file.

The algorithm here uses the PRNG seeded with a high entropy source to insert a block of data at the beginning of the file. This data is the first data encrypted. On decryption, the first block of data is discarded, restoring the original file. Since the algorithm is designed so that single bit changes avalanche throughout the file, this initial block of data that is introduced makes the same file encrypt differently each time it is encrypted with the same key.

Background

In Bruce Schneier's book "Applied Cryptography", he spoke of a block cipher where each block is XORed with the hash of the previous block's cipher text concatenated with the key.

A simple variation on this theme is to XOR the first block with the hash of the key and XOR subsequent blocks with the previous block's plain text and the hash used on the previous block.

Since the starting hash was generated from the key, the key still avalanches throughout the cipher text since each hash is used to generate the next block's hash.

Using the Code

The attached source code was developed to demonstrate the principal described above. It was developed using Visual C++ as a console application. All the code is in a single file; not very pretty but it works.

Points of Interest

On my 3GHz dual core Pentium, the code encrypts and decrypts at a rate of 8MB/s.

History

  • 22nd July, 2008: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Unknown
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralUpdated to include passphrase validation Pin
Tom Stone8-Mar-09 15:51
Tom Stone8-Mar-09 15:51 
GeneralUpdated code, includes bug fixes Pin
Tom Stone19-Dec-08 9:35
Tom Stone19-Dec-08 9:35 
<br />
#include <io.h><br />
#include <stdio.h><br />
#include <stdlib.h><br />
#include <memory.h><br />
#include <string.h><br />
#include <comutil.h><br />
#include <time.h><br />
<br />
#pragma once<br />
/*<br />
SHA256 is from this source<br />
 ---------------------------------------------------------------------------<br />
 Copyright (c) 2002, Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK.<br />
 All rights reserved.<br />
<br />
 LICENSE TERMS<br />
<br />
 The free distribution and use of this software in both source and binary <br />
 form is allowed (with or without changes) provided that:<br />
<br />
   1. distributions of this source code include the above copyright <br />
      notice, this list of conditions and the following disclaimer;<br />
<br />
   2. distributions in binary form include the above copyright<br />
      notice, this list of conditions and the following disclaimer<br />
      in the documentation and/or other associated materials;<br />
<br />
   3. the copyright holder's name is not used to endorse products <br />
      built using this software without specific written permission. <br />
<br />
 ALTERNATIVELY, provided that this notice is retained in full, this product<br />
 may be distributed under the terms of the GNU General Public License (GPL),<br />
 in which case the provisions of the GPL apply INSTEAD OF those given above.<br />
 <br />
 DISCLAIMER<br />
<br />
 This software is provided 'as is' with no explicit or implied warranties<br />
 in respect of its properties, including, but not limited to, correctness <br />
 and/or fitness for purpose.<br />
 ---------------------------------------------------------------------------<br />
 Issue Date: 30/11/2002<br />
*/<br />
<br />
#ifndef _SHA2_H<br />
#define _SHA2_H<br />
<br />
#include <limits.h><br />
<br />
/*  Defines for suffixes to 32 and 64 bit unsigned numeric values   */<br />
<br />
#define sfx_lo(x,y) x##y<br />
#define sfx_hi(x,y) sfx_lo(x,y)<br />
#define n_u32(p)    sfx_hi(0x##p,s_u32)<br />
#define n_u64(p)    sfx_hi(0x##p,s_u64)<br />
<br />
/* define an unsigned 32-bit type */<br />
<br />
#if UINT_MAX == 0xffffffff<br />
  typedef   unsigned int     sha2_32t;<br />
  #define s_u32    u<br />
#elif ULONG_MAX == 0xffffffff<br />
  typedef   unsigned long    sha2_32t;<br />
  #define s_u32   ul<br />
#else<br />
#error Please define sha2_32t as an unsigned 32 bit type in sha2.h<br />
#endif<br />
<br />
/* define an unsigned 64-bit type */<br />
<br />
#if defined( _MSC_VER )<br />
  typedef unsigned __int64   sha2_64t;<br />
  #define s_u64 ui64<br />
#elif ULONG_MAX == 0xffffffffffffffff<br />
  typedef unsigned long      sha2_64t;<br />
  #define s_u64   ul<br />
#elif ULONG_MAX == 0xffffffff<br />
  typedef unsigned long long sha2_64t;   /* a somewhat dangerous guess */<br />
  #define s_u64  ull<br />
#else<br />
#error Please define sha2_64t as an unsigned 64 bit type in sha2.h<br />
#endif<br />
<br />
#if defined(__cplusplus)<br />
extern "C"<br />
{<br />
#endif<br />
<br />
#define BYTES_PER_BLOCK     32<br />
#define BYTES_PER_WORD       4<br />
#define WORDS_PER_BLOCK     (BYTES_PER_BLOCK/BYTES_PER_WORD)<br />
#define REHASH_SIZE         (BYTES_PER_BLOCK*2)<br />
<br />
#define SHA256_DIGEST_SIZE  32<br />
#define SHA384_DIGEST_SIZE  48<br />
#define SHA512_DIGEST_SIZE  64<br />
<br />
#define SHA256_BLOCK_SIZE   64<br />
#define SHA384_BLOCK_SIZE  128<br />
#define SHA512_BLOCK_SIZE  128<br />
<br />
#define SHA2_DIGEST_SIZE        SHA256_DIGEST_SIZE<br />
#define SHA2_MAX_DIGEST_SIZE    SHA512_DIGEST_SIZE<br />
<br />
#define SHA2_GOOD   0<br />
#define SHA2_BAD    1<br />
<br />
/* type to hold the SHA256 context				*/<br />
<br />
typedef struct<br />
{   sha2_32t count[2];<br />
    sha2_32t hash[8];<br />
    sha2_32t wbuf[16];<br />
} sha256_ctx;<br />
<br />
/* type to hold the SHA384/512 context			*/<br />
<br />
typedef struct<br />
{   sha2_64t count[2];<br />
    sha2_64t hash[8];<br />
    sha2_64t wbuf[16];<br />
} sha512_ctx;<br />
<br />
typedef sha512_ctx  sha384_ctx;<br />
<br />
/* type to hold a SHA2 context (256/384/512)  */<br />
<br />
typedef struct<br />
{   union<br />
    {   sha256_ctx  ctx256[1];<br />
        sha512_ctx  ctx512[1];<br />
    } uu[1];<br />
    sha2_32t    sha2_len;<br />
} sha2_ctx;<br />
<br />
void sha256_compile(sha256_ctx ctx[1]);<br />
void sha512_compile(sha512_ctx ctx[1]);<br />
<br />
void sha256_begin(sha256_ctx ctx[1]);<br />
void sha256_hash(const unsigned char data[], unsigned long len, sha256_ctx ctx[1]);<br />
void sha256_end(unsigned char hval[], sha256_ctx ctx[1]);<br />
void sha256(unsigned char hval[], const unsigned char data[], unsigned long len); <br />
<br />
void sha384_begin(sha384_ctx ctx[1]);<br />
#define sha384_hash sha512_hash<br />
void sha384_end(unsigned char hval[], sha384_ctx ctx[1]);<br />
void sha384(unsigned char hval[], const unsigned char data[], unsigned long len); <br />
<br />
void sha512_begin(sha512_ctx ctx[1]);<br />
void sha512_hash(const unsigned char data[], unsigned long len, sha512_ctx ctx[1]);<br />
void sha512_end(unsigned char hval[], sha512_ctx ctx[1]);<br />
void sha512(unsigned char hval[], const unsigned char data[], unsigned long len); <br />
<br />
int sha2_begin(unsigned long size, sha2_ctx ctx[1]);<br />
void sha2_hash(const unsigned char data[], unsigned long len, sha2_ctx ctx[1]);<br />
void sha2_end(unsigned char hval[], sha2_ctx ctx[1]);<br />
int sha2(unsigned char hval[], unsigned long size, const unsigned char data[], unsigned long len); <br />
<br />
#if defined(__cplusplus)<br />
}<br />
#endif<br />
<br />
#endif<br />
<br />
#define MAX_WORDS 524288<br />
<br />
/* Period parameters */  <br />
#define N 624<br />
#define M 397<br />
#define MATRIX_A 0x9908b0dfUL   /* constant vector a */<br />
#define UPPER_MASK 0x80000000UL /* most significant w-r bits */<br />
#define LOWER_MASK 0x7fffffffUL /* least significant r bits */<br />
<br />
unsigned long genrand_int32(void);<br />
<br />
static unsigned long mt[N]; /* the array for the state vector  */<br />
static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */<br />
static unsigned long accum; /* the array for the state vector  */<br />
<br />
/* define the hash functions that you need          */<br />
<br />
#define SHA_2           /* for dynamic hash length  */<br />
#define SHA_256<br />
//#define SHA_384<br />
//#define SHA_512<br />
<br />
#include <string.h>     /* for memcpy() etc.        */<br />
#include <stdlib.h>     /* for _lrotr with VC++     */<br />
<br />
//#include "sha2.h"<br />
<br />
/*  1. PLATFORM SPECIFIC INCLUDES */<br />
<br />
#if defined(__GNU_LIBRARY__)<br />
#  include <byteswap.h><br />
#  include <endian.h><br />
#elif defined(__CRYPTLIB__)<br />
#  if defined( INC_ALL )<br />
#    include "crypt.h"<br />
#  elif defined( INC_CHILD )<br />
#    include "../crypt.h"<br />
#  else<br />
#    include "crypt.h"<br />
#  endif<br />
#  if defined(DATA_LITTLEENDIAN)<br />
#    define PLATFORM_BYTE_ORDER SHA_LITTLE_ENDIAN<br />
#  else<br />
#    define PLATFORM_BYTE_ORDER SHA_BIG_ENDIAN<br />
#  endif<br />
#elif defined(_MSC_VER)<br />
#  include <stdlib.h><br />
#elif !defined(WIN32)<br />
#  include <stdlib.h><br />
#  if !defined (_ENDIAN_H)<br />
#    include <br />
#  else<br />
#    include _ENDIAN_H<br />
#  endif<br />
#endif<br />
<br />
/*  2. BYTE ORDER IN 32-BIT WORDS<br />
<br />
    To obtain the highest speed on processors with 32-bit words, this code <br />
    needs to determine the order in which bytes are packed into such words.<br />
    The following block of code is an attempt to capture the most obvious <br />
    ways in which various environemnts specify their endian definitions. <br />
    It may well fail, in which case the definitions will need to be set by <br />
    editing at the points marked **** EDIT HERE IF NECESSARY **** below.<br />
*/<br />
#define SHA_LITTLE_ENDIAN   1234 /* byte 0 is least significant (i386) */<br />
#define SHA_BIG_ENDIAN      4321 /* byte 0 is most significant (mc68k) */<br />
<br />
#if !defined(PLATFORM_BYTE_ORDER)<br />
#if defined(LITTLE_ENDIAN) || defined(BIG_ENDIAN)<br />
#  if defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN)<br />
#    if defined(BYTE_ORDER)<br />
#      if   (BYTE_ORDER == LITTLE_ENDIAN)<br />
#        define PLATFORM_BYTE_ORDER SHA_LITTLE_ENDIAN<br />
#      elif (BYTE_ORDER == BIG_ENDIAN)<br />
#        define PLATFORM_BYTE_ORDER SHA_BIG_ENDIAN<br />
#      endif<br />
#    endif<br />
#  elif defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN) <br />
#    define PLATFORM_BYTE_ORDER SHA_LITTLE_ENDIAN<br />
#  elif !defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN)<br />
#    define PLATFORM_BYTE_ORDER SHA_BIG_ENDIAN<br />
#  endif<br />
#elif defined(_LITTLE_ENDIAN) || defined(_BIG_ENDIAN)<br />
#  if defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN)<br />
#    if defined(_BYTE_ORDER)<br />
#      if   (_BYTE_ORDER == _LITTLE_ENDIAN)<br />
#        define PLATFORM_BYTE_ORDER SHA_LITTLE_ENDIAN<br />
#      elif (_BYTE_ORDER == _BIG_ENDIAN)<br />
#        define PLATFORM_BYTE_ORDER SHA_BIG_ENDIAN<br />
#      endif<br />
#    endif<br />
#  elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) <br />
#    define PLATFORM_BYTE_ORDER SHA_LITTLE_ENDIAN<br />
#  elif !defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN)<br />
#    define PLATFORM_BYTE_ORDER SHA_BIG_ENDIAN<br />
#  endif<br />
#elif 0     /* **** EDIT HERE IF NECESSARY **** */<br />
#define PLATFORM_BYTE_ORDER SHA_LITTLE_ENDIAN<br />
#elif 0     /* **** EDIT HERE IF NECESSARY **** */<br />
#define PLATFORM_BYTE_ORDER SHA_BIG_ENDIAN<br />
#elif (('1234' >> 24) == '1')<br />
#  define PLATFORM_BYTE_ORDER SHA_LITTLE_ENDIAN<br />
#elif (('4321' >> 24) == '1')<br />
#  define PLATFORM_BYTE_ORDER SHA_BIG_ENDIAN<br />
#endif<br />
#endif<br />
<br />
#if !defined(PLATFORM_BYTE_ORDER)<br />
#  error Please set undetermined byte order (lines 159 or 161 of sha2.c).<br />
#endif<br />
<br />
#ifdef _MSC_VER<br />
#pragma intrinsic(memcpy)<br />
#endif<br />
<br />
#define rotr32(x,n)   (((x) >> n) | ((x) << (32 - n)))<br />
<br />
#if !defined(bswap_32)<br />
#define bswap_32(x) (rotr32((x), 24) & 0x00ff00ff | rotr32((x), 8) & 0xff00ff00)<br />
#endif<br />
<br />
#if (PLATFORM_BYTE_ORDER == SHA_LITTLE_ENDIAN)<br />
#define SWAP_BYTES<br />
#else<br />
#undef  SWAP_BYTES<br />
#endif<br />
<br />
#if defined(SHA_2) || defined(SHA_256)<br />
<br />
#define SHA256_MASK (SHA256_BLOCK_SIZE - 1)<br />
<br />
#if defined(SWAP_BYTES)<br />
#define	bsw_32(p,n)	{ int _i = (n);	while(_i--) p[_i] = bswap_32(p[_i]); }<br />
#else<br />
#define	bsw_32(p,n)	<br />
#endif<br />
<br />
/* SHA256 mixing function definitions   */<br />
<br />
#define ch(x,y,z)   (((x) & (y)) ^ (~(x) & (z)))<br />
#define maj(x,y,z)  (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))<br />
<br />
#define s256_0(x) (rotr32((x),  2) ^ rotr32((x), 13) ^ rotr32((x), 22)) <br />
#define s256_1(x) (rotr32((x),  6) ^ rotr32((x), 11) ^ rotr32((x), 25)) <br />
#define g256_0(x) (rotr32((x),  7) ^ rotr32((x), 18) ^ ((x) >>  3)) <br />
#define g256_1(x) (rotr32((x), 17) ^ rotr32((x), 19) ^ ((x) >> 10)) <br />
<br />
/* rotated SHA256 round definition. Rather than swapping variables as in    */<br />
/* FIPS-180, different variables are 'rotated' on each round, returning     */<br />
/* to their starting positions every eight rounds                           */<br />
<br />
#define h2(i) ctx->wbuf[i & 15] += \<br />
    g256_1(ctx->wbuf[(i + 14) & 15]) + ctx->wbuf[(i + 9) & 15] + g256_0(ctx->wbuf[(i + 1) & 15])<br />
<br />
#define h2_cycle(i,j)  \<br />
    v[(7 - i) & 7] += (j ? h2(i) : ctx->wbuf[i & 15]) + k256[i + j] \<br />
        + s256_1(v[(4 - i) & 7]) + ch(v[(4 - i) & 7], v[(5 - i) & 7], v[(6 - i) & 7]); \<br />
    v[(3 - i) & 7] += v[(7 - i) & 7]; \<br />
    v[(7 - i) & 7] += s256_0(v[(0 - i) & 7]) + maj(v[(0 - i) & 7], v[(1 - i) & 7], v[(2 - i) & 7])<br />
<br />
/* SHA256 mixing data   */<br />
<br />
const sha2_32t k256[64] =<br />
{   n_u32(428a2f98), n_u32(71374491), n_u32(b5c0fbcf), n_u32(e9b5dba5), <br />
    n_u32(3956c25b), n_u32(59f111f1), n_u32(923f82a4), n_u32(ab1c5ed5), <br />
    n_u32(d807aa98), n_u32(12835b01), n_u32(243185be), n_u32(550c7dc3), <br />
    n_u32(72be5d74), n_u32(80deb1fe), n_u32(9bdc06a7), n_u32(c19bf174), <br />
    n_u32(e49b69c1), n_u32(efbe4786), n_u32(0fc19dc6), n_u32(240ca1cc), <br />
    n_u32(2de92c6f), n_u32(4a7484aa), n_u32(5cb0a9dc), n_u32(76f988da), <br />
    n_u32(983e5152), n_u32(a831c66d), n_u32(b00327c8), n_u32(bf597fc7), <br />
    n_u32(c6e00bf3), n_u32(d5a79147), n_u32(06ca6351), n_u32(14292967), <br />
    n_u32(27b70a85), n_u32(2e1b2138), n_u32(4d2c6dfc), n_u32(53380d13), <br />
    n_u32(650a7354), n_u32(766a0abb), n_u32(81c2c92e), n_u32(92722c85),<br />
    n_u32(a2bfe8a1), n_u32(a81a664b), n_u32(c24b8b70), n_u32(c76c51a3), <br />
    n_u32(d192e819), n_u32(d6990624), n_u32(f40e3585), n_u32(106aa070), <br />
    n_u32(19a4c116), n_u32(1e376c08), n_u32(2748774c), n_u32(34b0bcb5), <br />
    n_u32(391c0cb3), n_u32(4ed8aa4a), n_u32(5b9cca4f), n_u32(682e6ff3), <br />
    n_u32(748f82ee), n_u32(78a5636f), n_u32(84c87814), n_u32(8cc70208), <br />
    n_u32(90befffa), n_u32(a4506ceb), n_u32(bef9a3f7), n_u32(c67178f2),<br />
};<br />
<br />
/* SHA256 initialisation data */<br />
<br />
const sha2_32t i256[8] =<br />
{<br />
    n_u32(6a09e667), n_u32(bb67ae85), n_u32(3c6ef372), n_u32(a54ff53a),<br />
    n_u32(510e527f), n_u32(9b05688c), n_u32(1f83d9ab), n_u32(5be0cd19)<br />
};<br />
<br />
<br />
void sha256_begin(sha256_ctx ctx[1])<br />
{<br />
    ctx->count[0] = ctx->count[1] = 0;<br />
    memcpy(ctx->hash, i256, 8 * sizeof(sha2_32t));<br />
}<br />
<br />
/* Compile 64 bytes of hash data into SHA256 digest value   */<br />
/* NOTE: this routine assumes that the byte order in the    */<br />
/* ctx->wbuf[] at this point is in such an order that low   */<br />
/* address bytes in the ORIGINAL byte stream placed in this */<br />
/* buffer will now go to the high end of words on BOTH big  */<br />
/* and little endian systems                                */<br />
<br />
void sha256_compile(sha256_ctx ctx[1])<br />
{   sha2_32t	v[8], j;<br />
<br />
    memcpy(v, ctx->hash, 8 * sizeof(sha2_32t));<br />
<br />
    for(j = 0; j < 64; j += 16)<br />
    {<br />
        h2_cycle( 0, j); h2_cycle( 1, j); h2_cycle( 2, j); h2_cycle( 3, j);<br />
        h2_cycle( 4, j); h2_cycle( 5, j); h2_cycle( 6, j); h2_cycle( 7, j);<br />
        h2_cycle( 8, j); h2_cycle( 9, j); h2_cycle(10, j); h2_cycle(11, j);<br />
        h2_cycle(12, j); h2_cycle(13, j); h2_cycle(14, j); h2_cycle(15, j);<br />
    }<br />
<br />
    ctx->hash[0] += v[0]; ctx->hash[1] += v[1]; ctx->hash[2] += v[2]; ctx->hash[3] += v[3];<br />
    ctx->hash[4] += v[4]; ctx->hash[5] += v[5]; ctx->hash[6] += v[6]; ctx->hash[7] += v[7];<br />
}<br />
<br />
/* SHA256 hash data in an array of bytes into hash buffer   */<br />
/* and call the hash_compile function as required.          */<br />
<br />
void sha256_hash(const unsigned char data[], unsigned long len, sha256_ctx ctx[1])<br />
{   sha2_32t pos = (sha2_32t)(ctx->count[0] & SHA256_MASK), <br />
             space = SHA256_BLOCK_SIZE - pos;<br />
    const unsigned char *sp = data;<br />
<br />
    if((ctx->count[0] += len) < len)<br />
        ++(ctx->count[1]);<br />
<br />
    while(len >= space)     /* tranfer whole blocks while possible  */<br />
    {<br />
        memcpy(((unsigned char*)ctx->wbuf) + pos, sp, space);<br />
        sp += space; len -= space; space = SHA256_BLOCK_SIZE; pos = 0; <br />
		bsw_32(ctx->wbuf, SHA256_BLOCK_SIZE >> 2)<br />
        sha256_compile(ctx);<br />
    }<br />
<br />
    memcpy(((unsigned char*)ctx->wbuf) + pos, sp, len);<br />
}<br />
<br />
/* SHA256 Final padding and digest calculation  */<br />
<br />
static sha2_32t  m1[4] =<br />
{<br />
    n_u32(00000000), n_u32(ff000000), n_u32(ffff0000), n_u32(ffffff00)<br />
};<br />
<br />
static sha2_32t  b1[4] =<br />
{<br />
    n_u32(80000000), n_u32(00800000), n_u32(00008000), n_u32(00000080)<br />
};<br />
<br />
void sha256_end(unsigned char hval[], sha256_ctx ctx[1])<br />
{   sha2_32t    i = (sha2_32t)(ctx->count[0] & SHA256_MASK);<br />
<br />
	bsw_32(ctx->wbuf, (i + 3) >> 2)<br />
    /* bytes in the buffer are now in an order in which references  */<br />
    /* to 32-bit words will put bytes with lower addresses into the */<br />
    /* top of 32 bit words on BOTH big and little endian machines   */<br />
    <br />
    /* we now need to mask valid bytes and add the padding which is */<br />
    /* a single 1 bit and as many zero bits as necessary.           */<br />
    ctx->wbuf[i >> 2] = (ctx->wbuf[i >> 2] & m1[i & 3]) | b1[i & 3];<br />
<br />
    /* we need 9 or more empty positions, one for the padding byte  */<br />
    /* (above) and eight for the length count.  If there is not     */<br />
    /* enough space pad and empty the buffer                        */<br />
    if(i > SHA256_BLOCK_SIZE - 9)<br />
    {<br />
        if(i < 60) ctx->wbuf[15] = 0;<br />
        sha256_compile(ctx);<br />
        i = 0;<br />
    }<br />
    else    /* compute a word index for the empty buffer positions  */<br />
        i = (i >> 2) + 1;<br />
<br />
    while(i < 14) /* and zero pad all but last two positions      */ <br />
        ctx->wbuf[i++] = 0;<br />
    <br />
    /* the following 32-bit length fields are assembled in the      */<br />
    /* wrong byte order on little endian machines but this is       */<br />
    /* corrected later since they are only ever used as 32-bit      */<br />
    /* word values.                                                 */<br />
<br />
    ctx->wbuf[14] = (ctx->count[1] << 3) | (ctx->count[0] >> 29);<br />
    ctx->wbuf[15] = ctx->count[0] << 3;<br />
<br />
    sha256_compile(ctx);<br />
<br />
    /* extract the hash value as bytes in case the hash buffer is   */<br />
    /* mislaigned for 32-bit words                                  */<br />
    for(i = 0; i < SHA256_DIGEST_SIZE; ++i)<br />
        hval[i] = (unsigned char)(ctx->hash[i >> 2] >> 8 * (~i & 3));<br />
}<br />
<br />
void sha256(unsigned char hval[], const unsigned char data[], unsigned long len) <br />
{   sha256_ctx  cx[1];<br />
    <br />
    sha256_begin(cx); sha256_hash(data, len, cx); sha256_end(hval, cx);<br />
}<br />
<br />
#endif<br />
<br />
#if defined(SHA_2)<br />
<br />
#define CTX_256(x)  ((x)->uu->ctx256)<br />
<br />
/* SHA2 initialisation */<br />
<br />
int sha2_begin(unsigned long len, sha2_ctx ctx[1])<br />
{   unsigned long   l = len;<br />
    switch(len)<br />
    {<br />
        case 256:   l = len >> 3;<br />
        case  32:   CTX_256(ctx)->count[0] = CTX_256(ctx)->count[1] = 0;<br />
                    memcpy(CTX_256(ctx)->hash, i256, 32); break;<br />
<br />
        default:    return SHA2_BAD;<br />
    }<br />
    <br />
    ctx->sha2_len = l; return SHA2_GOOD;<br />
}<br />
<br />
void sha2_hash(const unsigned char data[], unsigned long len, sha2_ctx ctx[1])<br />
{<br />
    switch(ctx->sha2_len)<br />
    {<br />
        case 32: sha256_hash(data, len, CTX_256(ctx)); return;<br />
<br />
    }<br />
}<br />
<br />
void sha2_end(unsigned char hval[], sha2_ctx ctx[1])<br />
{<br />
    switch(ctx->sha2_len)<br />
    {<br />
        case 32: sha256_end(hval, CTX_256(ctx)); return;<br />
<br />
    }<br />
}<br />
<br />
int sha2(unsigned char hval[], unsigned long size,<br />
                                const unsigned char data[], unsigned long len)<br />
{   sha2_ctx    cx[1];<br />
<br />
    if(sha2_begin(256, cx) == SHA2_GOOD)<br />
    {<br />
        sha2_hash(data, len, cx); sha2_end(hval, cx); return SHA2_GOOD;<br />
    }<br />
    else<br />
        return SHA2_BAD;<br />
}<br />
<br />
#endif<br />
<br />
// The random number generator is based on the Mersenne Twistor<br />
// It has been modified to return the sum of the outputs<br />
<br />
/* <br />
   A C-program for MT19937, with initialization improved 2002/1/26.<br />
   Coded by Takuji Nishimura and Makoto Matsumoto.<br />
<br />
   Before using, initialize the state by using init_genrand(seed)  <br />
   or init_by_array(init_key, key_length).<br />
<br />
   Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,<br />
   All rights reserved.                          <br />
<br />
   Redistribution and use in source and binary forms, with or without<br />
   modification, are permitted provided that the following conditions<br />
   are met:<br />
<br />
     1. Redistributions of source code must retain the above copyright<br />
        notice, this list of conditions and the following disclaimer.<br />
<br />
     2. Redistributions in binary form must reproduce the above copyright<br />
        notice, this list of conditions and the following disclaimer in the<br />
        documentation and/or other materials provided with the distribution.<br />
<br />
     3. The names of its contributors may not be used to endorse or promote <br />
        products derived from this software without specific prior written <br />
        permission.<br />
<br />
   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS<br />
   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT<br />
   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR<br />
   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR<br />
   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,<br />
   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,<br />
   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR<br />
   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF<br />
   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING<br />
   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS<br />
   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.<br />
<br />
<br />
   Any feedback is very welcome.<br />
   http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html<br />
   email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)<br />
*/<br />
<br />
<br />
/* initializes mt[N] with a seed */<br />
void init_genrand(unsigned long s)<br />
{<br />
    mt[0]= s & 0xffffffffUL;<br />
    accum = 0;<br />
    for (mti=1; mti<n;>        mt[mti] = <br />
	    (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti); <br />
        /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */<br />
        /* In the previous versions, MSBs of the seed affect   */<br />
        /* only MSBs of the array mt[].                        */<br />
        /* 2002/01/09 modified by Makoto Matsumoto             */<br />
        mt[mti] &= 0xffffffffUL;<br />
        /* for >32 bit machines */<br />
    }<br />
}<br />
<br />
/* initialize by an array with array-length */<br />
/* init_key is the array for initializing keys */<br />
/* key_length is its length */<br />
/* slight change for C++, 2004/2/26 */<br />
void init_by_array(unsigned long init_key[], int key_length)<br />
{<br />
    int i, j, k, dummy;<br />
<br />
    memset(mt, 0, 4*N);<br />
    init_genrand(19650218UL);<br />
    i=1; j=0;<br />
<br />
<br />
<br />
    k = (N>key_length ? N : key_length);<br />
    for (; k; k--) {<br />
        mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL))<br />
          + init_key[j] + j; /* non linear */<br />
        mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */<br />
        i++; j++;<br />
        if (i>=N) { mt[0] = mt[N-1]; i=1; }<br />
        if (j>=key_length) j=0;<br />
    }<br />
    for (k=N-1; k; k--) {<br />
        mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL))<br />
          - i; /* non linear */<br />
        mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */<br />
        i++;<br />
        if (i>=N) { mt[0] = mt[N-1]; i=1; }<br />
    }<br />
<br />
    mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */ <br />
<br />
    for (i=0; i<64; i++) dummy = genrand_int32();<br />
<br />
}<br />
<br />
/* generates a random number on [0,0xffffffff]-interval */<br />
unsigned long genrand_int32(void)<br />
{<br />
    unsigned long y;<br />
    static unsigned long mag01[2]={0x0UL, MATRIX_A};<br />
    /* mag01[x] = x * MATRIX_A  for x=0,1 */<br />
<br />
    if (mti >= N) { /* generate N words at one time */<br />
        int kk;<br />
<br />
        if (mti == N+1)   /* if init_genrand() has not been called, */<br />
            init_genrand(5489UL); /* a default initial seed is used */<br />
<br />
        for (kk=0;kk<n-m;kk++)>            y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);<br />
            mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL];<br />
        }<br />
        for (;kk<n-1;kk++)>            y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);<br />
            mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL];<br />
        }<br />
        y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);<br />
        mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];<br />
<br />
        mti = 0;<br />
    }<br />
  <br />
    y = mt[mti++];<br />
<br />
    /* Tempering */<br />
    y ^= (y >> 11);<br />
    y ^= (y << 7) & 0x9d2c5680UL;<br />
    y ^= (y << 15) & 0xefc60000UL;<br />
    y ^= (y >> 18);<br />
<br />
    accum += y;<br />
<br />
    return accum;<br />
}<br />
<br />
#define ENCRYPT 0<br />
#define DECRYPT 1<br />
<br />
/*<br />
** The encryption algorithm is designed to provide some protection for the user<br />
** who re-uses the same pass phrase when encrypting various files.  The algorithm<br />
** will generate different cipher text even if it is invoked on the exact same plain<br />
** text with the same pass phrase.<br />
**<br />
** This is accomplished by cascading a stream cipher with a block cipher.  The stream<br />
** cipher uses a PRNG that is first seeded with both the passphrase and some high entropy<br />
** data and used to generate an initial 32-byte IV.  The IV concatenated with the passphrase<br />
** is used to seed the PRNG for the stream cipher.  The IV is encrypted by XORing it with <br />
** the hash of the passphrase and printing the encrypted IV as the initial 32 bytes of the <br />
** output file.<br />
**<br />
** Each block is calculated from the cipher text of the previous<br />
** block concatenated with the hash used to encrypt the previous block.<br />
**<br />
** The re-keyed stream cipher(IV+passphrase)is run against the cipher text generated by the<br />
** XORing of the hash.<br />
**<br />
** On decryption the first block is stripped.<br />
**<br />
** It is not as slow as I expected.  On a 3GHz dual core Pentium it encrypts 8MB/s<br />
**<br />
**<br />
*/<br />
<br />
int main(int argc, char * argv[])<br />
{<br />
    int IV_processed = 0;<br />
    FILE * fd_in, * fd_out;<br />
    unsigned char buffer_area[MAX_WORDS], keystream;<br />
    size_t bytes_read = 0;<br />
    unsigned int i, j, k, keysize = 0;<br />
    int eof, filename_size, direction, muddle = 0;<br />
    int start_fill, blocks_processed = 0;<br />
    char output_filename[1000];<br />
    const char * my_out = output_filename;<br />
    unsigned long multipart_key[N];<br />
    sha256_ctx m_sha256, m2_sha256;<br />
    unsigned char pBuf[4096], pTemp[256]; <br />
    unsigned long uRead = 0;<br />
<br />
    FILETIME idleTimePtr, kernelTimePtr, userTimePtr;<br />
<br />
    memset(buffer_area, 0, sizeof(buffer_area));<br />
    memset(output_filename, 0, sizeof(output_filename));<br />
<br />
    memset(multipart_key, 0, 4*N);<br />
    /*<br />
     ** for encryption<br />
     ** get high entropy seed for PRNG<br />
     ** use PRNG to generate 32 byte block<br />
     ** reseed the PRNG with KEY<br />
     */<br />
    GetSystemTimes(&idleTimePtr, &kernelTimePtr, &userTimePtr);<br />
    multipart_key[0] = idleTimePtr.dwLowDateTime;<br />
    multipart_key[1] = idleTimePtr.dwHighDateTime;<br />
    multipart_key[2] = kernelTimePtr.dwLowDateTime;<br />
    multipart_key[3] = kernelTimePtr.dwHighDateTime;<br />
    multipart_key[4] = userTimePtr.dwLowDateTime;<br />
    multipart_key[5] = userTimePtr.dwHighDateTime;<br />
    multipart_key[6] = time(NULL);<br />
    multipart_key[7] = clock();<br />
    /*<br />
     ** so much for the adding entropy stuff, now add the passphrase<br />
     */<br />
    char * string = argv[2];<br />
    for (i = 0; i < strlen(argv[2]); i++) {<br />
        multipart_key[WORDS_PER_BLOCK+(i>>2)] |= string[i] << (WORDS_PER_BLOCK*(i&3));<br />
    }<br />
    keysize = (i >> 2) + 1;<br />
    if (i&3) keysize++;<br />
    keysize += WORDS_PER_BLOCK;<br />
    init_by_array(&multipart_key[0], keysize);<br />
    /*<br />
     ** Clear out the first BYTES_PER_BLOCK bytes of the multipart_key, the passphrase portion will be re-used<br />
     */<br />
    memset(&multipart_key[0], 0, BYTES_PER_BLOCK);<br />
    /*<br />
     ** generate the 32 byte IV in case we are encrypting<br />
     */<br />
    for (i = 0; i < BYTES_PER_BLOCK; i++) {<br />
        buffer_area[i] = genrand_int32() >> 24;<br />
    }<br />
    /*<br />
     ** put the IV into the key for reseeding the PRNG when encrypting the file<br />
     */<br />
    for (k = 0; k < BYTES_PER_BLOCK; k++) {<br />
        multipart_key[(k>>2)] |= buffer_area[k] << (WORDS_PER_BLOCK*(k&3));<br />
    }<br />
<br />
    if (argc == 1) {<br />
        printf("Invoke encryption using\n\n");<br />
        printf("   \"%s file passphrase\"\n", argv[0]);<br />
        printf("Encrypted/decrypted output will be the filename with an\nunderscore appended/removed\n");<br />
        printf("The encrypted file will be 32 bytes larger than the plain text file\n");<br />
        exit(0);<br />
    } else {<br />
        if (argc < 3) {<br />
            printf("too few arguments\n");<br />
            exit(0);<br />
        }<br />
    }<br />
<br />
<br />
    if (argc >= 3) {<br />
        strcpy((char *)&pBuf[0], argv[2]);<br />
        sha256_begin(&m_sha256);<br />
        sha256_hash(pBuf, (unsigned long)strlen(argv[2]), &m_sha256);<br />
        sha256_end(pTemp, &m_sha256);<br />
    } else {<br />
        printf("insufficient arguments\n");<br />
        exit(0);<br />
    }<br />
<br />
    if (_access((const char *)argv[1], 0) != 0) {<br />
        printf("file does not exist\n");<br />
        exit(0);<br />
    } <br />
<br />
    filename_size = strlen(argv[1]);<br />
    strcpy(output_filename, argv[1]);<br />
    if (output_filename[filename_size-1] == 0x5f) {<br />
        direction = DECRYPT;<br />
        output_filename[filename_size-1] = 0;<br />
        start_fill = 0;<br />
    } else {<br />
        direction = ENCRYPT;<br />
        output_filename[filename_size] = 0x5f;<br />
        start_fill = BYTES_PER_BLOCK;<br />
        init_by_array(&multipart_key[0], keysize);<br />
    }<br />
<br />
    fd_in = fopen((const char *)argv[1], (const char *)("rb"));<br />
    fd_out = fopen(my_out, (const char *)("wb"));<br />
    /*<br />
     ** for each 32 byte block<br />
     **    compute next blocks hash<br />
     **    for each byte in block<br />
     **       a(i) = a(i-1) + p(i) & 0xff<br />
     **       apply p(i) ^= a(i-1)<br />
     **       apply p(i) ^= k(i)<br />
     **    endfor<br />
     **    block ^= current blocks hash<br />
     ** endfor<br />
     */<br />
<br />
<br />
    do {<br />
        bytes_read = fread( &buffer_area[start_fill], 1, (MAX_WORDS-start_fill), fd_in);<br />
        bytes_read += start_fill;<br />
        blocks_processed++;<br />
        i = 0;<br />
        while (i < bytes_read) {<br />
            if (ENCRYPT == direction) {<br />
                if ((i % BYTES_PER_BLOCK) == 0) {<br />
                    for (j = i; j <= i+BYTES_PER_BLOCK-1; j++) {<br />
                        pBuf[j%BYTES_PER_BLOCK] = buffer_area[i+(j%BYTES_PER_BLOCK)];<br />
                    }<br />
                }<br />
                if (((i+1) % BYTES_PER_BLOCK) == 0) { // calculate hash for next block<br />
                    for (j=0; j<8; j++) {<br />
                        pBuf[BYTES_PER_BLOCK+4*j] = (m_sha256.hash[j] >> 24) & 0xff;<br />
                        pBuf[BYTES_PER_BLOCK+1+4*j] = (m_sha256.hash[j] >> 16) & 0xff;<br />
                        pBuf[BYTES_PER_BLOCK+2+4*j] = (m_sha256.hash[j] >> 8) & 0xff;<br />
                        pBuf[BYTES_PER_BLOCK+3+4*j] =  m_sha256.hash[j] & 0xff;<br />
                    }  <br />
                    sha256_begin(&m2_sha256);<br />
                    sha256_hash(pBuf, REHASH_SIZE, &m2_sha256);<br />
                    sha256_end(pTemp, &m2_sha256);<br />
                }<br />
                buffer_area[i] ^= m_sha256.hash[((i%BYTES_PER_BLOCK)/BYTES_PER_WORD)] >> ((i%4)*8);<br />
                /* the 32 byte IV is only XORed with the hash */<br />
                if ((blocks_processed > 1) || (i>(BYTES_PER_BLOCK-1))) {<br />
                    keystream = genrand_int32() >> 24;<br />
                    buffer_area[i] ^= keystream;<br />
                }<br />
                if ((++i % BYTES_PER_BLOCK) == 0) { // transfer new hash into current hash<br />
<br />
                    memcpy(&m_sha256, &m2_sha256, sizeof(m_sha256));<br />
                }<br />
            } else { // DECRYPT<br />
                /*<br />
                 ** to decrypt<br />
                 ** for each block<br />
                 ** stream and hash<br />
                 ** calculate next hash<br />
                 */<br />
<br />
                buffer_area[i] ^= m_sha256.hash[((i%BYTES_PER_BLOCK)/BYTES_PER_WORD)] >> ((i%4)*8);<br />
                if (IV_processed) {<br />
                    keystream = genrand_int32() >> 24;<br />
                    buffer_area[i] ^= keystream;<br />
                }<br />
<br />
                if (blocks_processed == 1) {/* not processed IV yet? */<br />
                    if (i == (BYTES_PER_BLOCK-1)) {         /* is this the end of the IV */<br />
                        memset(&multipart_key[0], 0, BYTES_PER_BLOCK);<br />
                        IV_processed = 1;   /* set IV to processed */<br />
                        for (k = 0; k < BYTES_PER_BLOCK; k++) {<br />
                            multipart_key[(k>>2)] |= buffer_area[k] << (8*(k&3));<br />
                        }<br />
<br />
                        init_by_array(&multipart_key[0], keysize);<br />
                    }<br />
                }<br />
                if (((i+1) % BYTES_PER_BLOCK) == 0) {<br />
                    for (j = i-(BYTES_PER_BLOCK-1); j <= i; j++) {<br />
                        pBuf[0 + (j-i+BYTES_PER_BLOCK-1)] = buffer_area[j];<br />
                    }<br />
                    for (j=0; j<8; j++) {<br />
                        pBuf[BYTES_PER_BLOCK+4*j] = (m_sha256.hash[j] >> 24) & 0xff;<br />
                        pBuf[BYTES_PER_BLOCK+1+4*j] = (m_sha256.hash[j] >> 16) & 0xff;<br />
                        pBuf[BYTES_PER_BLOCK+2+4*j] = (m_sha256.hash[j] >> 8) & 0xff;<br />
                        pBuf[BYTES_PER_BLOCK+3+4*j] =  m_sha256.hash[j] & 0xff;<br />
                    }<br />
                   sha256_begin(&m_sha256);<br />
                    sha256_hash(pBuf, REHASH_SIZE, &m_sha256);<br />
                    sha256_end(pTemp, &m_sha256);<br />
                }<br />
                i++;<br />
            }<br />
        }<br />
        if ((DECRYPT == direction) && (blocks_processed == 1)) {<br />
            fwrite(&buffer_area[BYTES_PER_BLOCK],1,bytes_read-BYTES_PER_BLOCK,fd_out);<br />
        } else {<br />
            fwrite(&buffer_area[0],1,bytes_read,fd_out);<br />
        }<br />
        start_fill = 0;<br />
        eof = feof(fd_in);<br />
    } while (eof == 0);<br />
<br />
    fclose(fd_in);<br />
    fclose(fd_out);<br />
    exit(0);<br />
}<br />
<br />
</stdlib.h></stdlib.h></endian.h></byteswap.h></stdlib.h></string.h></limits.h></time.h></comutil.h></string.h></memory.h></stdlib.h></stdio.h></io.h>

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.