PDA

View Full Version : criptografia C ANSII


felix
07-14-2004, 10:19 PM
Hi,

I need a code to add rijndael to one of my code, so i searched in internet to a C ANSI source that implement rijndael, so i found this:

http://efgh.com/software/rijndael.txt

Until know ok, the problem is that i create a func that receive data (with different sizes, for example, some times 5 , 11, 32, 56 at most 128) and i want to bypass it to a func that will encript it with rijndael and write to a file, i done something like that:

unsigned long rk[RKLENGTH(KEYBITS)];
unsigned char key[KEYLENGTH(KEYBITS)];
int i;
int nrounds;
char chave[]="TestKey";
char *password;

password = chave;

for (i = 0; i < sizeof(key); i++){

key[i] = password != 0 ? *password++ : 0;

}

nrounds = rijndaelSetupEncrypt(rk, key, 256);

unsigned char plaintext[size];
unsigned char ciphertext[size];

//memset(plaintext, '\0', size);
//memset(ciphertext, '\0', size);

for (i = 0; i < size; i++){

plaintext[i] = s != 0 ? *s++ : 0;

}

rijndaelEncrypt(rk, nrounds, plaintext, ciphertext);
fwrite(ciphertext, sizeof(size) , size, file);
fflush(file);

}

I'm calling this function in this way:

char buff[128] = "\0";
some routines to get and copy data into buff
some routines to get and copy data into buff
some routines to get and copy data into buff
EncryptRij((unsigned char *)buff, 128);

But it isn't work fine! :(

I belive that it can be a problem related with padding in crypt, null bytes or something related. As i'm a really newba in crypt i don't know how to __debug__ it! Can someone help me in try to make it work ?

ps.: It need be in C ANSII because i need it run over win and linux. :)

Regards.

Thkz a lot.

i3839
07-15-2004, 12:24 AM
Rijndael encrypts in blocks of 16 bytes, and a lot Rijndael encryption functions expect 16 bytes blocks, at least the one you use seems to do. So just call the encryption function in a loop in 16 bytes blocks until the last block. That one you need to treat specially because it's most likely not aligned at 16 bytes, thus you need either padding or some other trick. Then the question is how big the padding is, so you need to store that somewhere...

Mind that you can make the encryption much safer if you use chain block coding (CBC mode), which means you do a xor between the result of the first block with the data of the second block, and so on for all blocks, chainging them together because you can't decrypt a seperate block anymore, but need to decrypt the whole file first.

Mind that Rijndael is just a block cipher, on it self it doesn't implement higher level encryption stuff like CBC mode etc. You can't go much lower. You could also use a higher level more general encryption library, like libcrypt, but I would use Rijndael directly.

felix
07-15-2004, 05:03 PM
Hi i3839,

Thkz for reply.

Well, i choosed Rijndael beucase i had read several articles that describe it as one of bests, since it is the AES (new version ?), and several articles describe it as very security.

1 - This CBC is a kind of encrypt like rijndael or it can be used with rijndael like a plus ? For example i encrypt 2 bocks with rijndael and the make the XOR between ths two ?

2 - I thinked in libcrypt but i need it work under windows, and over win it is build with .dll, and i intend to doesn't use external modules (like .dll, .ocx, etc). Only the executable.

3 - Only CBC is more secure than Rijndael ?

4 - To encrypt data i noted that a kind of resource (time) is used. What is the impact with CDC ? Rijndael ? Rijndael + CBC ?

Sorry for dummys question..

Regards.

i3839
07-15-2004, 05:57 PM
1: Rijndael is just a block cipher, all it does is (d)encrypt a block of 16 bytes with a given key, nothing else. There are many ways how to encrypt bigger data structures, and one of such ways is encrypting it in CBC mode. So you can encrypt in CBC mode with any block cipher. See for instance http://www.networksorcery.com/enp/data/encryption.htm for some more info, or try Google.

Example with 3 blocks of 16 bytes:

[B1] [B2] [B3]

Get a random block R1.
do B1 XOR R1 with as result B1x.
encrypt B1x with as result b1x.
do b1x XOR B2 with as result B2x.
encrypt B2x with as result b2x.
do b2x XOR B3 -> B3x.
encrypt B3x -> b3x.
do b3x XOR R1 -> R1x.
encrypt R1x -> r1x.

Result:

[b1x] [b2x] [b3x] [r1x]

Now you need to decrypt all blocks before you can get the original data of any block, making it 'numblocks' times harder to break the encryption. This is very useful with plain text because text doesn't have much variantion in it so it's relative very easy to crack encrypted text. Only thing is that modern encryption is so good that it's IMHO not really needed to do things like that, better to use a longer key and spare yourself the trouble.

But crypto people are very paranoid. If you as cracker can choose the input and know the encrypted output, and can do that multiple times, and you can guess/find the encryption key, then they say the encryption cipher is insecure. Mind that you can let whatever you want be encrypted, and variate just one bit each time, and still have no clue what the encryption key is, also not after years of trying.

2: Not that I want to encourage you to use libcrypt, but you can simply link statically to it if there are no license problems.

3: See above. It can be used to make the result more secure, but IMHO if they can crack one block then they can crack the rest too, and you're not important enough for them to waste millions on thousands of parallel decryption boxes trying to guess your key. The nice thing of CBC is that it's very cheap, xoring is much faster than encryption, so for not too small files and such, especially if they are stored for a longer time, it's worth doing. The main disadvantage is that you can't decrypt CBC in a streaming way, that it's more complicated, and that handling the initialisation key (R1) can be tricky, although they have methods where R1 can be anything and doesn't have to be kept secret.

4: That recourse is mostly used for random initialisation data like R1, and for a random encryption key. The point is, how secure Rijdael may be, if they know how you make your keys then it may be very easy to guess your key for them, so NEVER use time as a recourse for random data. Use /dev/urandom in Linux, that is a very good resource for real random data.

felix
07-16-2004, 09:01 PM
Hi i3839,

Well, thkz once again for help me with my dumb questions ;)

1 - I understood the basic diferences and had read the link and other papers on web. I'm thinking in bue the B. Scheiner book Applyed crypt in C & C++! Someone already had read ? Is good ? Easy ?

Backing to the "problem".

2 - I'm thinking in use this CBC with Rijndael, so i need first make it work weel. I done this fix that you should me:

* Only manipulate 16 bytes (in a for())
* Put padding (space) where is '\0'

My code now is like that:

void *EncryptRij (register unsigned char *s, size_t size){

unsigned long rk[RKLENGTH(KEYBITS)];
unsigned char key[KEYLENGTH(KEYBITS)];
int i;
int x;
int loop;
int nrounds;
char secret[]="TestKey";
char *password;

password = secret;

for (i = 0; i < sizeof(key); i++){

key[i] = password != 0 ? *password++ : 0;

}

nrounds = rijndaelSetupEncrypt(rk, key, 256);

loop = size / 16;

for ( x = 0; x <= loop; x++){

unsigned char plaintext[16]="\0";
unsigned char ciphertext[16]="\0";

for (i = 0; i < 16 ; i++){

plaintext[i] = s != 0 ? *s++ : 0;

}

for (; i < 16 ; i++){

plaintext[i] = ' ';

}

rijndaelEncrypt(rk, nrounds, plaintext, ciphertext);
fwrite(ciphertext, sizeof(ciphertext) , 1, fp);
fflush(fp);

}

}

I think, that now my code is correct, i'm sure ? :)

Then i call it like that:

EncryptRij((unsigned char *)buff, 128);

And open the file to write, like that (open binary and for append):

fp = fopen(file, "ab");

Well, some diference i already noted. Since the file doesn't contain more plain-text! :)

So, when i decrypt with my key "TestKey" using the decrypt from URL in the first post (that i think should work with my file, since i use padding too, the 16bytes encrypt peer time, etc).

The code for decrypt is that:

#include <stdio.h>
#include "rijndael.h"

#define KEYBITS 256

int main(int argc, char **argv)
{
unsigned long rk[RKLENGTH(KEYBITS)];
unsigned char key[KEYLENGTH(KEYBITS)];
int i;
int nrounds;
char *password;
FILE *input;
if (argc < 3)
{
fputs("Missing argument", stderr);
return 1;
}
password = argv[1];
for (i = 0; i < sizeof(key); i++)
key[i] = password != 0 ? *password++ : 0;
input = fopen(argv[2], "rb");
if (input == NULL)
{
fputs("File read error", stderr);
return 1;
}
nrounds = rijndaelSetupDecrypt(rk, key, 256);
while (1)
{
unsigned char plaintext[16];
unsigned char ciphertext[16];
int j;
if (fread(ciphertext, sizeof(ciphertext), 1, input) != 1)
break;
rijndaelDecrypt(rk, nrounds, ciphertext, plaintext);
fwrite(plaintext, sizeof(plaintext), 1, stdout);
}
fclose(input);
}

But the output yet "appear" encrypted.. hehehe

ps.: I'm only using ASCII code to don't have problems with the encrypt/decrypt.

What is wrong with that ?

ps.: Work with cryot is very HARD do debug. The normal way i do, use printf(), test values, etc, doesn't haven much utility with crypt! :( What do you do in general ?

3 - I was thinking, if my code have a key build-in in the code, like my example

char secret[]="TestKey";

So where is the security if some attacker can simple debug my binary and read the value of the var secret ? :?

Thkz a lot.

Regards.

i3839
07-16-2004, 10:08 PM
I wouldn't buy that book I think, if I would buy a book then one only about encryption, that one seems not really serious. But better to read the reviews than to trust me who just judges it by the title.

Some quick notes about your code:

"register unsigned char *s" doesn't make sense, just use "char *s".

That nrounds thing is something else than you think. Rijndael does various actions on the input depending on the key, if the key is longer than there can be done more actions and the data can be encrypted better. That encryption process is divided in rounds. So that nrounds of you is internal Rijndael stuff that's done for each block.

You forget the rest value, except if you demand size to be a multiple of 16, but then it's better to check that. E.g. if size is 17 then you have two blocks, one 0-15, and one 16 padded with zeros.

Ever heard of strcpy, memcpy and memset? (See manpages)

You work with binary data, not with strings, so stuff like plaintext[16]="\0" is totally useless. Why not keeping it simple and do something like:

char ciphertext[16];
for (i=0; i < size/16; i+=16){
rijndaelEncrypt(rk, nrounds, s+i, ciphertext);
fwrite(ciphertext, sizeof(ciphertext), 1, fp);
}
int rest = size%16;
if (rest){
lastblock[16];
memset(lastblock, 0, sizeof(lastblock));
memcpy(lastblock, s+size - rest, rest);
rijndaelEncrypt(rk, nrounds, lastblock, ciphertext);
fwrite(ciphertext, sizeof(ciphertext), 1, fp);
}
fflush(fp);

That rest thing is only needed if size can be something else than a multiple of 16, but that's what you probably want if you make a higher level wrapper function.

Just use dummy encrypt functions when debugging, that's a good start. If that's not good enough then you could make a very simple one yourself (e.g. one that swaps all bytes) and use plaintext as input. Then the decrypted output is readable and you can try to figure out what goes wrong. The best is to not make any mistakes in the first place, that's what I go for. ;-)

Well, as for point 3: It's just a test key. In the final version you would want to get they key from somewhere else, like a file. In theory putting the string in the binary isn't that unsafe, if only the user can read the binary (and if each binary has a unique key of course). It's just damn unpractical.

As a last remark, that encryption API you use doesn't seem that great, there are better versions out there. It's in the public domain though...

felix
07-23-2004, 03:55 PM
Hi i3839,

Thkz again! :)


wouldn't buy that book I think, if I would buy a book then one only about encryption, that one seems not really serious. But better to read the reviews than to trust me who just judges it by the title.

The author have a good fame, he who created the famous blowfish http://www.schneier.com/blowfish.html!

Anyway i found on web a copy of it, if someone are interested in a copy send-me a PM! :)

"register unsigned char *s" doesn't make sense, just use "char *s".

I use register to try allocate directily in register to run fastily.
The unsigned i used because all the implementation use unsigned char, so to don't create more possibilities of code doesn't work i used it too. :)

You forget the rest value, except if you demand size to be a multiple of 16, but then it's better to check that. E.g. if size is 17 then you have two blocks, one 0-15, and one 16 padded with zeros.

I was passing the size value always as 128 as test, but know i pass the reutrn of strlen().

Ever heard of strcpy, memcpy and memset? (See manpages)

Yes, hehehehe! But as i said the code doesn't use it, so i tryed to make a more identical possible to work without problems. Then if it worked i will improve and test... :)

You work with binary data, not with strings, so stuff like plaintext[16]="\0" is totally useless. Why not keeping it simple and do something like:

Really better than my code.. :)

That rest thing is only needed if size can be something else than a multiple of 16, but that's what you probably want if you make a higher level wrapper function.

Well, this code wasn't work properly, until i start to call it like:

EncryptRij((unsigned char *)buff, strlen(buff));

Intead the old:

EncryptRij((unsigned char *)buff, 128);

Ok, now it print the entirily strings, before it, was only printed the first 16!

A intersting thing is that the encryption/decryption doesn't work yet! :(

As you spoken i used dummy crypt (or no crypt) to test it and see as it is showed, i done that:

unsigned long rk[RKLENGTH(KEYBITS)];
unsigned char key[KEYLENGTH(KEYBITS)];
int i;
int x;
int loop;
int nrounds;
char secret[]="TestKey";
char *password;

password = secret;

for (i = 0; i < sizeof(key); i++){

key[i] = password != 0 ? *password++ : 0;

}

nrounds = rijndaelSetupEncrypt(rk, key, 256);

unsigned char ciphertext[16];
for (i=0; i < size/16; i+=16){

rijndaelEncrypt(rk, nrounds, s+i, ciphertext);
//fwrite(ciphertext, sizeof(ciphertext), 1, fp);
fwrite(s+i, 16, 1, fp);

}

int rest = size%16;

if (rest){

unsigned char lastblock[16];
memset(lastblock, 0, sizeof(lastblock));
//lastblock[16] = '\n'; // This shit doesn't work
memcpy(lastblock, s+size-rest, rest);
rijndaelEncrypt(rk, nrounds, lastblock, ciphertext);
//fwrite(ciphertext, sizeof(ciphertext), 1, fp);
fwrite(s+size-rest, 16, 1, fp);

}
fflush(fp);

So the code was printed perfectily... but when call crypt doesn't work.. :(

I searched at web, and saw that a common problem is padding with zero and doesn't work against Rijndael, and solution should be use space, so i changed:

memset(lastblock, 0, sizeof(lastblock));

By:

memset(lastblock, ' ', sizeof(lastblock));

But the code doesn't work yet.. :(

That's the hell!! hehehehe

Ideas ?

Just use dummy encrypt functions when debugging, that's a good start. If that's not good enough then you could make a very simple one yourself (e.g. one that swaps all bytes) and use plaintext as input. Then the decrypted output is readable and you can try to figure out what goes wrong. The best is to not make any mistakes in the first place, that's what I go for.

I'm trying do it... ;)

Well, as for point 3: It's just a test key. In the final version you would want to get they key from somewhere else, like a file.

Hummm, if a cracker only open that file ? So, he have the key, and the encryption was inutilly... :(

Ok, you can say: "But he doesn't know the file".

It can be true, but he can debug application and discover, or better, simple hook some systemcalls like sys_open() and see all you open.. So in this case the security is nothing.. o.O

In theory putting the string in the binary isn't that unsafe, if only the user can read the binary (and if each binary has a unique key of course). It's just damn unpractical.

Well, supose that the file need to be acessed by everyone in the machine (including admin), so we can't restrict the file. So what should us do ?

As a last remark, that encryption API you use doesn't seem that great, there are better versions out there. It's in the public domain though...

Could you share with us what do you use ?? Maybe a example.. hehee ;)

Thkz a lot for all help and sorry to be so persistent...

Regards.

i3839
07-23-2004, 07:38 PM
Being able to make good ciphers doesn't mean you're a good writer too. I would still try to find some sort of review, even if it's an amazon users' review. You do understand that after reading the book you must use blowfish instead of rijndael though. ;-)

I hope that that webcopy of you is legal. If not...

Making only that pointer a register won't speed anything up at all, better to keep your code clean and when it works optimize it, if needed at all (keep in mind that the encryption will probably use 99% of your program's cpu usage, so optimizing that 1% with stuff like "register" doesn't really help).

Don't use a string as password, not even as a test password, but if you do it then make it exactly the same size as your key so that you don't have random stack garbage at the end of the key. (In other words, I think you forgot to pad your key)

Rijndael doesn't care about what it gets, zeroes or spaces, it's only you that handles the data as strings instead of binary data. Even if you know for sure that it's only strings you get you should handle it as random data.

About the security: Encryption is so good nowaday that it's all about how you handle your keys, that's one of the reasons why asymmetric encryption where you use different keys to encrypt and decrypt data is so popular: Even if the server is hacked, then still they don't know the client's private key (ssh for instance).

What they do is encrypting the key with a passphrase. Then when someone wants to use that key he needs to give the pass. Because an encryption key is more or less random they can't know if they guessed your pass correctly. Of course it's not really secure because when they do have some data, e.g. a file, then they can guess your pass, try to decrypt the file, and if that returns apparently the correct result (text) then they know your key. But it's better than nothing, and there are some tricks to make it harder (e.g. encrypting it insanely many times, so that it takes long to just decrypt the key with one pass).

Most times it's that if they can read your files and run programs under your user account then they can already do all the damage they want, so they don't really need your key for anything. Your security is as strong as your key is hidden. Best would be if you keep any encryption key encrypted with a passphrase on removable media like a usb stick. Then they need physical access to your media first before they can start guessing your pass, but if they reach that point you can annoy them a bit by using CBC mode so that guessing your pass takes longer (because to verify each guess they need to decrypt much more data before they know if it's correct). There are also other modes than CBC which may be better, although they are sometimes patented so you can't use it. :-(

I used the well known implementation of Brian Gladman, mainly because that was the smallest binary implementation (after compilation with certain config settings). I wanted to use it in a little remote shell server program (something like sshd) the target was to keep it under 12Kb statically linked. It was a fun project, but because of the lack of any need for it I never finished it (no one will use it anyway I guess, and I don't really need it either). Besides, that pseudo tty stuff was getting on my nerves.

You can find Gladman's and some other implementations here (http://rijndael.com/implementations.html). Most implementations have a simple test program included, so you can take a look at those.

Nothing wrong with being persistant, if you get too annoying I'll just ignore you. ;-)

felix
07-27-2004, 09:32 PM
Hi i3839,

Thkz a lot again! :)

I think that i will start to search about assymetric encription (will be best for my tests). ;)

And anyway i will try the implementation from Brian Gladman. ;)

Thkz a lot again.

Regards.

i3839
07-27-2004, 10:29 PM
Asymmetric encryption compared to symmetric encryption is:

Much slower. So in general they only use it for handshaking, after that they use a normal block cipher with a temporary random key which they just agreed on. Or encrypt the data quickly, and encrypt the just used random symmetric key with an asymmetric cipher.

Less secure, and security isn't as proven as that of good block ciphers. This means in practice that you need bigger keys, e.g. 256 bits or more as minimum. For Rijndael for instance 128 is enough for quite a while.

Very good for authentication stuff. You can prove that you are who you say you are by encrypting something, it can be verified by decrypting it with the public decryption key. With symmetric encryption you both need to know the key, so you can't use it in cases where the verifying side isn't totally trusted. Mind that authentication is something else than encryption, although for both the same ciphers can be used.

mlampkin
07-28-2004, 07:32 AM
Just a quick interjection...

Asymmetric algorithms generally have a much larger range of possible values for the key(s) as compared to the symmetric algorithms... meaning that among other things the asymmetric systems are generally more secure ( not less ) than symmetric since they are less susceptible to exhaustive key searches / attacks...

Michael

i3839
07-28-2004, 03:02 PM
Isn't that only the case with ciphers that have weak keys, like DES?

felix
07-28-2004, 03:17 PM
Hi i3839 & mlampkin,

Thzk for reply once again!

Only a comment that i forgoten, i think that the problem in the last source of rijndael isn't related with padding of key, because is the default implementation he does the some and work for stdin. I will check it, anyway...

I thinked in use assymetric encryption like that:

A binary pre-builded with the public Key in the machine insecure, saving all data crypted. So i copy the data encrypted to a machine in other place where i have the private key created to that public key in binary and decrypt it. I think that in this way i will increase the secure... ;)

Some idea or suggestions for algorithms or implementations of assymetric encryption ?

I was looking at RSA, but i found several documents describing possibles evendrops.. o.O

Regards.