PDA

View Full Version : Crypto Library Help Please!


Clandestiny
September 26th, 2003, 21:54
Hi guys,

This is probably a lame question, but I swear I'm near my wits end here. I'm looking for a well documented library in C that has the algorithms DES, Triple DES, and Blowfish...And let me re-emphasize *WELL* documented and preferably basic! So far I have attempted to use both crypto++ and cryptlib without success. My C++ skills are limited and trying to use crypto++ was hopeless for me as it seemed to be heavily object oriented with very poor documentation, IMHO. Cryptlib struck me as much better as it is thankfully in plain C, however, the documentation was somewhat lacking as well and I'm having a devil of a time figuring out wtf I'm doing. I'm such a crypto newbie, I had to even look up what the difference between the CBC and CFB modes . I'm trying to encrypt an ascii string so I assume that the CFB would be most appropriate as its more of a stream cipher.

Here is some code that I have trying to use the cryptLib. Unfortunately, I doesn't work at all.
//set up initialization vector variables
char iv[CRYPT_MAX_IVSIZE] = {0};
CRYPT_CONTEXT cryptContext = {0};
memset(iv, '0', CRYPT_MAX_IVSIZE);

//create the encryption context for the DES algorithm
cryptCreateContext(&cryptContext, CRYPT_UNUSED,CRYPT_ALGO_DES);
//set up the initialization vector
cryptSetAttributeString(cryptContext,CRYPT_CTXINFO_IV,iv,8);
//insert the key into the context
cryptSetAttributeString(cryptContext, CRYPT_CTXINFO_KEY,password, 8 );
//set as a stream cipher
cryptSetAttribute( cryptContext, CRYPT_CTXINFO_MODE, CRYPT_MODE_CFB );
//encrypt the plaintext
cryptEncrypt(cryptContext,cryptarray,1);
cryptDestroyContext(cryptContext);
return cryptarray;

Also, I was wondering about the best way to hash a password string into a key. For example, Blowfish has a 448 bit key. What is the best way to convert a string into this giant key? I know these questions belong on a crypto-forum-for-newbies , but I'll appreciate any help I can get

Thanks,
Clandestiny

dELTA
September 26th, 2003, 23:29
Blowfish has a variable length key, it does not have to be e.g. 448 bits (which is not the maximum keylength either, if I'm not mistaken). Simply use the password itself as key. If you necessarily want to expand it, you could for example simply repeat the password until it fills up the desired length. Since the entropy of the key will not increase no matter what kind of hashing function you use, this is just as good as any other method.

mike
September 27th, 2003, 04:41
Well, lucky you! I work with Peter Gutmann on cryptlib, and wrote the java interface for it.

First thing--did you call cryptInit? If not, nothing else will work.

Second, what do you need it to do? If you're just looking to do basic password-based encryption, use the enveloping api.

Third, I know the manual needs someone to reorganize it. However, there's a great mailing list with an archive, explaining lots of stuff with example code.

Fourth, if you can wait until Monday morning New Zealand time, I can post some very simple source code that illustrates the steps you need.

Clandestiny
September 28th, 2003, 21:55
Thanks for the advice dELTA and Mike

Mike, it was my lucky day . Thanks for the info. I think I got some basic password based encryption to work using the cryptEncrypt function. As I understand it, this is the low-level interface. I would be interested in how the higher level eneloping API works, but IMHO the documentation wasn't too clear on the matter and I was just happy to finally get *something* to work. Can you specify a specific encryption algorithm to be used in the eveloping API or does it just assign it automatically?

Bearing in mind that this is coming from a crypto newbie
I'd like to make a few suggestions regarding the documentation...

1. I realize there are several modes for the block ciphers including the CBC, CFB, and OFB. I didn't feel that the documention was really clear in indicating which modes are supported for which algorithms. Likewise, it would have been helpful to have some more documentation about restrictions on the function parameters based on which mode you're operating in.

2. It would have been very helpful to have a listing of error codes that can be potentially returned for each function. The documentation simply defines each function as returning an int and I had to actually look in the header files to realize that it was a status value being returned.

3. Some example code comparing / contrasting a basic implementation at both the high level and the low level interfaces.

Thanks,
Clandestiny

mike
September 29th, 2003, 00:42
The docs are written for someone who knows what they're doing; I agree that it's very hard for a newbie to figure it out.

Archives:
ftp://ftp.franken.de/pub/crypt/cryptlib/archives/

1. The mode and the cipher are orthogonal. If it's a block cipher, it supports all the block cipher modes.

2. Error codes: p.212 in my version of the PDF. Try a text search for "error codes"

3. Here's some Java code illustrating the enveloping api with public/private keys. It's not exactly what you're trying to do, but it shows all the steps (one of the big failings of the docs IMO). If there's something about it you can't figure out, write back and I'll explain.

See p.47 "Password-based enveloping" and p. 202 "Working with Configuration Options" for choosing the underlying cipher for more info on doing what you want.


Code:

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;

import com.cryptlib.*;

class Demo implements CryptLibConstants
{
public static void main(String[] args)
{
CryptLib cl=CryptLib.getInstance();
int[] cryptEnvelope = new int[1];
int[] bytesCopied = new int[1];
int[] keys = new int[1];
byte[] buffer = new byte[10000];
int [] cert = new int[1];
int [] sigContext = new int[1];
int [] cryptContext = new int[1];
PrintStream stdout = System.out;
String bob = new String("Bob";
String paul = new String("Paul";

int result = CRYPT_OK;
int len=0;

// C equivalent of "try {" where "break out" replaces "throw"
out: do
{
try {
stdout.println("Initializing...";
if ((result = cl.cryptInit()) != CRYPT_OK) break out;

stdout.println("Generating keys...";
if ((result = cl.cryptKeysetOpen(keys, CRYPT_UNUSED, CRYPT_KEYSET_FILE, "SampleKeys", CRYPT_KEYOPT_CREATE)) != CRYPT_OK) break out;

if ((result = cl.cryptCreateContext(cryptContext,CRYPT_UNUSED,CRYPT_ALGO_RSA))!=CRYPT_OK)break out;
if ((result = cl.cryptSetAttributeString(cryptContext[0],CRYPT_CTXINFO_LABEL,bob.getBytes("UTF8",bob.length()))!=CRYPT_OK)break out;
if ((result = cl.cryptGenerateKey(cryptContext[0]))!=CRYPT_OK)break out;
if ((result = cl.cryptAddPrivateKey(keys[0],cryptContext[0],"test-bob")!=CRYPT_OK)break out;
if ((result = cl.cryptDestroyContext(cryptContext[0]))!=CRYPT_OK)break out;

if ((result = cl.cryptCreateContext(cryptContext,CRYPT_UNUSED,CRYPT_ALGO_RSA))!=CRYPT_OK)break out;
if ((result = cl.cryptSetAttributeString(cryptContext[0],CRYPT_CTXINFO_LABEL,paul.getBytes("UTF8",paul.length()))!=CRYPT_OK)break out;
if ((result = cl.cryptGenerateKey(cryptContext[0]))!=CRYPT_OK)break out;
if ((result = cl.cryptAddPrivateKey(keys[0],cryptContext[0],"test-paul")!=CRYPT_OK)break out;
if ((result = cl.cryptDestroyContext(cryptContext[0]))!=CRYPT_OK)break out;

if ((result = cl.cryptKeysetClose(keys[0])) != CRYPT_OK) break out;


// SIGN

stdout.println("Creating signature envelope...";
if ((result = cl.cryptCreateEnvelope( cryptEnvelope, CRYPT_UNUSED, CRYPT_FORMAT_CRYPTLIB )) != CRYPT_OK) break out;

stdout.println("Setting data size...";
if ((result = cl.cryptSetAttribute( cryptEnvelope[0], CRYPT_ENVINFO_DATASIZE, 11 )) != CRYPT_OK) break out;

stdout.println("Setting signing key...";
if ((result = cl.cryptKeysetOpen(keys, CRYPT_UNUSED, CRYPT_KEYSET_FILE, "SampleKeys", CRYPT_KEYOPT_READONLY)) != CRYPT_OK) break out;

if ((result = cl.cryptCreateContext(sigContext,CRYPT_UNUSED,CRYPT_ALGO_RSA))!=CRYPT_OK)break out;
if ((result = cl.cryptGetPrivateKey(keys[0], sigContext, CRYPT_KEYID_NAME, bob, "test-bob" )) != CRYPT_OK) break out;
if ((result = cl.cryptSetAttribute(cryptEnvelope[0], CRYPT_ENVINFO_SIGNATURE, sigContext[0] )) != CRYPT_OK) break out;

if ((result = cl.cryptKeysetClose(keys[0])) != CRYPT_OK) break out;

stdout.println("Pushing data...";
if ((result = cl.cryptPushData( cryptEnvelope[0], "Hello world".getBytes("UTF8", 11, bytesCopied )) != CRYPT_OK) break out;

stdout.println("Flushing data...";
if ((result = cl.cryptFlushData( cryptEnvelope[0] )) != CRYPT_OK) break out;

stdout.println("Popping data...";
if ((result = cl.cryptPopData( cryptEnvelope[0], buffer, 1000, bytesCopied )) != CRYPT_OK) break out;

stdout.println(bytesCopied[0]+" bytes out";
stdout.println("Destroying envelope...";
if ((result = cl.cryptDestroyEnvelope( cryptEnvelope[0] )) != CRYPT_OK) break out;
if ((result = cl.cryptDestroyContext( sigContext[0] )) != CRYPT_OK) break out;


// ENCRYPT


stdout.println("Creating encryption envelope...";
if ((result = cl.cryptCreateEnvelope( cryptEnvelope, CRYPT_UNUSED, CRYPT_FORMAT_CRYPTLIB )) != CRYPT_OK) break out;

stdout.println("Setting data size...";
if ((result = cl.cryptSetAttribute( cryptEnvelope[0], CRYPT_ENVINFO_DATASIZE, bytesCopied[0] )) != CRYPT_OK) break out;

stdout.println("Setting encryption key...";
if ((result = cl.cryptKeysetOpen(keys, CRYPT_UNUSED, CRYPT_KEYSET_FILE, "SampleKeys", CRYPT_KEYOPT_READONLY)) != CRYPT_OK) break out;

if ((result = cl.cryptCreateContext(cryptContext,CRYPT_UNUSED,CRYPT_ALGO_RSA))!=CRYPT_OK)break out;
if ((result = cl.cryptGetPublicKey(keys[0], cryptContext, CRYPT_KEYID_NAME, paul)) != CRYPT_OK) break out;
if ((result = cl.cryptSetAttribute(cryptEnvelope[0], CRYPT_ENVINFO_PUBLICKEY, cryptContext[0] )) != CRYPT_OK) break out;

if ((result = cl.cryptKeysetClose(keys[0])) != CRYPT_OK) break out;

stdout.println("Pushing data...";
if ((result = cl.cryptPushData( cryptEnvelope[0], buffer, bytesCopied[0], bytesCopied )) != CRYPT_OK) break out;

stdout.println("Flushing data...";
if ((result = cl.cryptFlushData( cryptEnvelope[0] )) != CRYPT_OK) break out;

stdout.println("Popping data...";
if ((result = cl.cryptPopData( cryptEnvelope[0], buffer, 1000, bytesCopied )) != CRYPT_OK) break out;

stdout.println(bytesCopied[0]+" bytes out";
for (int i=0; i<bytesCopied[0]; ++i)
{
stdout.print(buffer[I]+" ";
}
stdout.println("";

stdout.println("Destroying encryption envelope...";
if ((result = cl.cryptDestroyEnvelope( cryptEnvelope[0] )) != CRYPT_OK) break out;
if ((result = cl.cryptDestroyContext( cryptContext[0] )) != CRYPT_OK) break out;


// Now do everything in reverse...

// DECRYPT

stdout.println("Creating decryption envelope...";
if ((result = cl.cryptCreateEnvelope( cryptEnvelope, CRYPT_UNUSED, CRYPT_FORMAT_AUTO )) != CRYPT_OK) break out;

stdout.println("Pushing data...";
if ((result = cl.cryptPushData( cryptEnvelope[0], buffer, bytesCopied[0], bytesCopied )) != CRYPT_OK)
{
if (result != CRYPT_ENVELOPE_RESOURCE) { break out; }
}

stdout.println("Setting decryption key...";
if ((result = cl.cryptKeysetOpen(keys, CRYPT_UNUSED, CRYPT_KEYSET_FILE, "SampleKeys", CRYPT_KEYOPT_READONLY)) != CRYPT_OK) break out;

if ((result = cl.cryptCreateContext(cryptContext,CRYPT_UNUSED,CRYPT_ALGO_RSA))!=CRYPT_OK)break out;
if ((result = cl.cryptGetPrivateKey( keys[0], cryptContext, CRYPT_KEYID_NAME, paul, "test-paul" )) != CRYPT_OK) break out;
if ((result = cl.cryptSetAttribute( cryptEnvelope[0], CRYPT_ENVINFO_PRIVATEKEY, cryptContext[0] )) != CRYPT_OK) break out;

if ((result = cl.cryptKeysetClose(keys[0])) != CRYPT_OK) break out;

stdout.println("Flushing data...";
if ((result = cl.cryptFlushData( cryptEnvelope[0] )) != CRYPT_OK) break out;

stdout.println("Popping data...";
if ((result = cl.cryptPopData( cryptEnvelope[0], buffer, 1000, bytesCopied )) != CRYPT_OK) break out;

stdout.println(bytesCopied[0]+" bytes out";

stdout.println("Destroying decryption envelope...";
if ((result = cl.cryptDestroyEnvelope( cryptEnvelope[0] )) != CRYPT_OK) break out;
if ((result = cl.cryptDestroyContext( cryptContext[0] )) != CRYPT_OK) break out;


// VERIFY


stdout.println("Creating verification envelope...";
if ((result = cl.cryptCreateEnvelope( cryptEnvelope, CRYPT_UNUSED, CRYPT_FORMAT_AUTO )) != CRYPT_OK) break out;

stdout.println("Pushing data...";
if ((result = cl.cryptPushData( cryptEnvelope[0], buffer, bytesCopied[0], bytesCopied )) != CRYPT_OK)
{
if (result != CRYPT_ENVELOPE_RESOURCE) { break out; }
}

stdout.println("Setting verifying key...";
if ((result = cl.cryptKeysetOpen(keys, CRYPT_UNUSED, CRYPT_KEYSET_FILE, "SampleKeys", CRYPT_KEYOPT_READONLY)) != CRYPT_OK) break out;

if ((result = cl.cryptCreateContext(sigContext,CRYPT_UNUSED,CRYPT_ALGO_RSA))!=CRYPT_OK)break out;
if ((result = cl.cryptGetPublicKey( keys[0], sigContext, CRYPT_KEYID_NAME, bob )) != CRYPT_OK) break out;
if ((result = cl.cryptSetAttribute( cryptEnvelope[0], CRYPT_ENVINFO_SIGNATURE, sigContext[0] )) != CRYPT_OK) break out;

if ((result = cl.cryptKeysetClose(keys[0])) != CRYPT_OK) break out;

stdout.println("Flushing data...";
if ((result = cl.cryptFlushData( cryptEnvelope[0] )) != CRYPT_OK) break out;

stdout.println("Popping data...";
if ((result = cl.cryptPopData( cryptEnvelope[0], buffer, 1000, bytesCopied )) != CRYPT_OK) break out;

byte[] message = new byte[bytesCopied[0]];
stdout.println(bytesCopied[0]+" bytes out";

for (int i=0; i<bytesCopied[0]; ++i)
{
stdout.print(buffer[I]+" ";
message[I] = buffer[I];
}
// End-of-line
stdout.println("";

stdout.println("As string:";
stdout.println(new String(message,"UTF8");

stdout.println("Destroying verification envelope...";
if ((result = cl.cryptDestroyEnvelope( cryptEnvelope[0] )) != CRYPT_OK) break out;
if ((result = cl.cryptDestroyContext( sigContext[0] )) != CRYPT_OK) break out;

}
catch (UnsupportedEncodingException e)
{
stdout.println("Bad encoding?";
break out;
}
} while (false);

// C "catch"
if (result != CRYPT_OK)
{
stdout.println("Couldn't proceed: "+result);
}
stdout.println("Shutting down...";
cl.cryptEnd();
}
}