Mawg
Mawg

Reputation: 40159

Seeking single file encryption implemenation which can handle whole file en/de-crypt in Delphi and C

[Update] I am offering a bonus for this. Frankly, I don't care which encryption method is used. Preferably something simple like XTEA, RC4, BlowFish ... but you chose.

I want minimum effort on my part, preferably just drop the files into my projects and build.

Idealy you should already have used the code to en/de-crypt a file in Delphi and C (I want to trade files between an Atmel UC3 micro-processor (coding in C) and a Windows PC (coding in Delphi) en-and-de-crypt in both directions).

I have a strong preference for a single .PAS unit and a single .C/.H file. I do not want to use a DLL or a library supporting dozens of encryption algorithms, just one (and I certainly don't want anything with an install program).

I hope that I don't sound too picky here, but I have been googling & trying code for over a week and still can't find two implementations which match. I suspect that only someone who has already done this can help me ...

Thanks in advance.


As a follow up to my previous post, I am still looking for some very simple code with why I can - with minimal effort - en-de crypt a file and exchange it between Delphi on a PC and C on an Atmel UC3 u-processor.

It sounds simple in theory, but in practice it's a nightmare. There are many possible candidates and I have spend days googling and trying them out - to no avail.

Some are humonous libraries, supporting many encryption algorithms, and I want something lightweight (especially on the C / u-processor end).

Some look good, but one set of source offers only block manipulation, the other strings (I would prefer whole file en/de-crypt).

Most seem to be very poorly documented, with meaningless parameter names and no example code to call the functions.

Over the past weekend (plus a few more days), I have burned my way through a slew of XTEA, XXTEA and BlowFish implementations, but while I can encrypt, I can't reverse the process.

Now I am looking at AES-256. Dos anyone know of an implementation in C which is a single AES.C file? (plus AES.H, of course)

Frankly, I will take anything that will do whole file en/de-crypt between Delphi and C, but unless anyone has actually done this themselves, I expect to hear only "any implementation that meets the standard should do" - which is a nice theoory but just not working out for me :-(

Any simple AES-256 in C out there? I have some reasonable looking Delphi code, but won't be sure until I try them together.

Thanks in advance ...

Upvotes: 11

Views: 1345

Answers (6)

user1899861
user1899861

Reputation:

Assuming the encryption strength isn't an issue, as in satisfying an organization's Chinese Wall requirement, the very simple "Sawtooth" encryption scheme of adding (i++ % modulo 256) to fgetc(), for each byte, starting at the beginning of the file, might work just fine.

Declaring i as a UCHAR will eliminate the modulo requirement, as the single byte integer cannot help but cycle through its 0-255 range.

The code is so simple it's not worth posting. A little imagination, and you'll have some embellishments that can add a lot to the strength of this cypher. The primary vulnerability of this cypher is large blocks of identical characters. Rectifying this is a good place to start improving its strength.

This cypher works on every possible file type, and is especially effective if you've already 7Zipped the file.

Performance is phenomenal. You won't even know the code is there. Totally I/O bound.

Upvotes: 1

Gene
Gene

Reputation: 46960

Here is RC4 code. It is very lightweight.

The C has been used in a production system for five years.

I have added lightly tested Delphi code. The Pascal is a line-by-line port with with unsigned char going to Byte. I have only run the Pascal in Free Pascal with Delphi option turned on, not Delphi itself. Both C and Pascal have simple file processors.

Scrambling the ciphertext gives the original cleartext back.

No bugs reported to date. Hope this solves your problem.

rc4.h

#ifndef RC4_H
#define RC4_H

/*
 * rc4.h -- Declarations for a simple rc4 encryption/decryption implementation.
 * The code was inspired by libtomcrypt.  See www.libtomcrypt.org.
 */
typedef struct TRC4State_s {
  int x, y;
  unsigned char buf[256];
} TRC4State;

/* rc4.c */
void init_rc4(TRC4State *state);
void setup_rc4(TRC4State *state, char *key, int keylen);
unsigned endecrypt_rc4(unsigned char *buf, unsigned len, TRC4State *state);

#endif

rc4.c

void init_rc4(TRC4State *state)
{
  int x;
  state->x = state->y = 0;
  for (x = 0; x < 256; x++)
    state->buf[x] = x;
}

void setup_rc4(TRC4State *state, char *key, int keylen)
{
  unsigned tmp;
  int x, y;

  // use only first 256 characters of key 
  if (keylen > 256) 
    keylen = 256;

  for (x = y = 0; x < 256; x++) {
    y = (y + state->buf[x] + key[x % keylen]) & 255;
    tmp = state->buf[x]; 
    state->buf[x] = state->buf[y]; 
    state->buf[y] = tmp;
  }
  state->x = 255;
  state->y = y;
}

unsigned endecrypt_rc4(unsigned char *buf, unsigned len, TRC4State *state)
{
  int x, y; 
  unsigned char *s, tmp;
  unsigned n;

  x = state->x;
  y = state->y;
  s = state->buf;
  n = len;
  while (n--) {
    x = (x + 1) & 255;
    y = (y + s[x]) & 255;
    tmp = s[x]; s[x] = s[y]; s[y] = tmp;
    tmp = (s[x] + s[y]) & 255;
    *buf++ ^= s[tmp];
  }
  state->x = x;
  state->y = y;
  return len;
}

int endecrypt_file(FILE *f_in, FILE *f_out, char *key)
{
  TRC4State state[1];
  unsigned char buf[4096];
  size_t n_read, n_written;

  init_rc4(state);
  setup_rc4(state, key, strlen(key));
  do {
    n_read = fread(buf, 1, sizeof buf, f_in);
    endecrypt_rc4(buf, n_read, state);
    n_written = fwrite(buf, 1, n_read, f_out);
  } while (n_read == sizeof buf && n_written == n_read);
  return (n_written == n_read) ? 0 : 1;
}

int endecrypt_file_at(char *f_in_name, char *f_out_name, char *key)
{
  int rtn;

  FILE *f_in = fopen(f_in_name, "rb");
  if (!f_in) {
    return 1;
  }
  FILE *f_out = fopen(f_out_name, "wb");
  if (!f_out) {
    close(f_in);
    return 2;
  }
  rtn = endecrypt_file(f_in, f_out, key);
  fclose(f_in);
  fclose(f_out);
  return rtn;
}

#ifdef TEST

// Simple test.
int main(void)
{
  char *key = "This is the key!";

  endecrypt_file_at("rc4.pas", "rc4-scrambled.c", key);
  endecrypt_file_at("rc4-scrambled.c", "rc4-unscrambled.c", key);
  return 0;
}
#endif

Here is lightly tested Pascal. I can scramble the source code in C and descramble it with the Pascal implementation just fine.

type
  RC4State = record
    x, y : Integer;
    buf : array[0..255] of Byte;
  end;

  KeyString = String[255];

procedure initRC4(var state : RC4State);
var
  x : Integer;
begin
  state.x := 0;
  state.y := 0;
  for x := 0 to 255 do
    state.buf[x] := Byte(x);
end;

procedure setupRC4(var state : RC4State; var key : KeyString);
var
  tmp : Byte;
  x, y : Integer;
begin
  y := 0;
  for x := 0 to 255 do begin
    y := (y + state.buf[x] + Integer(key[1 + x mod Length(key)])) and 255;
    tmp := state.buf[x];
    state.buf[x] := state.buf[y];
    state.buf[y] := tmp;
  end;
  state.x := 255;
  state.y := y;
end;

procedure endecryptRC4(var buf : array of Byte; len : Integer; var state : RC4State);
var
  x, y, i : Integer;
  tmp : Byte;
begin
  x := state.x;
  y := state.y;
  for i := 0 to len - 1 do begin
    x := (x + 1) and 255;
    y := (y + state.buf[x]) and 255;
    tmp := state.buf[x];
    state.buf[x] := state.buf[y];
    state.buf[y] := tmp;
    tmp := (state.buf[x] + state.buf[y]) and 255;
    buf[i] := buf[i] xor state.buf[tmp]
  end;
  state.x := x;
  state.y := y;
end;

procedure endecryptFile(var fIn, fOut : File; key : KeyString);
var
  nRead, nWritten : Longword;
  buf : array[0..4095] of Byte;
  state : RC4State;
begin
  initRC4(state);
  setupRC4(state, key);
  repeat
    BlockRead(fIN, buf, sizeof(buf), nRead);
    endecryptRC4(buf, nRead, state);
    BlockWrite(fOut, buf, nRead, nWritten);
  until (nRead <> sizeof(buf)) or (nRead <> nWritten);
end;

procedure endecryptFileAt(fInName, fOutName, key : String);
var
  fIn, fOut : File;
begin
  Assign(fIn, fInName);
  Assign(fOut, fOutName);
  Reset(fIn, 1);
  Rewrite(fOut, 1);
  endecryptFile(fIn, fOut, key);
  Close(fIn);
  Close(fOut);
end;

{$IFDEF TEST}
// Very small test.
const
  key = 'This is the key!';
begin
  endecryptFileAt('rc4.pas', 'rc4-scrambled.pas', key);
  endecryptFileAt('rc4-scrambled.pas', 'rc4-unscrambled.pas', key);
end.
{$ENDIF}

Upvotes: 1

Leonix Solutions
Leonix Solutions

Reputation: 31

Can you compile C code from Delphi (you can compile Delphi code from C++ Builder, not sure about VV). Or maybe use the Free Borland Command line C++ compiler or even another C compiler.

The idea is to use the same C code in your Windows app as you use on your microprocessor.. That way you can be reasonably sure that the code will work in both directions.


[Update] See

http://www.drbob42.com/examines/examin92.htm
http://www.hflib.gov.cn/e_book/e_book_file/bcb/ch06.htm (Using C++ Code in Delphi)
http://edn.embarcadero.com/article/10156#H11

It looks like you need to use a DLL, but you can statically link it if you don't want to distribute it

Upvotes: 2

mr&#243;wa
mr&#243;wa

Reputation: 5771

Small C library for AES-256 by Ilya Levin. Short implementation, asm-less, simple usage. Not sure how would it work on your current micro CPU, though.

[Edit]
You've mentioned having some delphi implementation, but in case something not working together, try this or this.
Also I've found arduino (avr-based) module using the Ilya's library - so it should also work on your micro CPU.

Upvotes: 2

Nickolay Olshevsky
Nickolay Olshevsky

Reputation: 14160

It looks easier would be to get reference AES implementation (which works with blocks), and add some code to handle CBC (or CTR encryption). This would need from you only adding ~30-50 lines of code, something like the following (for CBC):

aes_expand_key();

first_block = iv;

for (i = 0; i < filesize / 16; i++)
{
  data_block = read(file, 16);
  data_block = (data_block ^ iv);
  iv = encrypt_block(data_block);
  write(outputfile, iv);  
}

// if filesize % 16 != 0, then you also need to add some padding and encrypt the last block

Upvotes: 1

Polynomial
Polynomial

Reputation: 28316

I would suggest using the .NET Micro Framework on a secondary microcontroller (e.g. Atmel SAM7X) as a crypto coprocessor. You can test this out on a Netduino, which you can pick up for around $35 / £30. The framework includes an AES implementation within it, under the System.Security.Cryptography namespace, alongside a variety of other cryptographic functions that might be useful for you. The benefit here is that you get a fully tested and working implementation, and increased security via type-safe code.

You could use SPI or I2C to communicate between the two microcontrollers, or bit-bang your own data transfer protocol over several I/O lines in parallel if higher throughput is needed.

I did exactly this with an Arduino and a Netduino (using the Netduino to hash blocks of data for a hardware BitTorrent device) and implemented a rudimentary asynchronous system using various commands sent between the devices via SPI and an interrupt mechanism.

  • Arduino is SPI master, Netduino is SPI slave.
  • A GPIO pin on the Netduino is set as an output, and tied to another interrupt-enabled GPIO pin on the Arduino that is set as an input. This is the interrupt pin.
  • Arduino sends 0xF1 as a "hello" initialization message.
  • Netduino sends back 0xF2 as an acknolwedgement.
  • When Arduino wants to hash a block, it sends 0x48 (ASCII 'H') followed by the data. When it is done sending data, it sets CS low. It must send whole bytes; setting CS low when the number of received bits is not divisible by 8 causes an error.
  • The Netduino receives the data, and sends back 0x68 (ASCII 'h') followed by the number of received bytes as a 2-byte unsigned integer. If an error occurred, it sends back 0x21 (ASCII '!') instead.
  • If it succeeded, the Netduino computes the hash, then sets the interrupt pin high. During the computation time, the Arduino is free to continue its job whilst waiting.
  • The Arduino sends 0x52 (ASCII 'R') to request the result.
  • The Netduino sets the interrupt pin low, then sends 0x72 (ASCII 'r') and the raw hash data back.

Since the Arduino can service interrupts via GPIO pins, it allowed me to make the processing entirely asynchronous. A variable on the Arduino side tracks whether we're currently waiting on the coprocessor to complete its task, so we don't try to send it a new block whilst it's still working on the old one.

You could easily adapt this scheme for computing AES blocks.

Upvotes: 2

Related Questions