Homepage | Download | Payment ] [ Logi Ragnarsson | Send Mail ]
General info | Status & Plans | FAQ | Commercial License | Class docs ]

The logi.crypto Frequently Asked Questions

Q: Where can I see some demonstration programs using logi.crypto?

A: See the test package.

There are a few demonstration and test programs in the org.logi.crypto.test package. More are included with the 1.1.x versions of the library.

Q: Why does DecryptCBC.decrypt() return an empty array?
On Tue, Feb 08, 2000 at 03:39:51AM +0800, Simon Liu Sai Man wrote:

Dear Logi,

I have downloaded your crypto library to perform encryption and decryption. However, I have faced a problem.

I have generated a RSA Key pair, and using CBC mode as Cryptographics mode.

I then pass a message, say "I am Neko", which is 9 bytes, to encrypt, by calling the method "EncryptCBC.encrypt(message,0,message.length)", which returns a byte array, with 128 bytes, say enc[].

And the I try using the private key to dectypt that message, by calling the method "DecryptCBC.decrypt(enc,0,enc.length)". However, it does not work, the return byte array with length 0.

So, are there any mistakes in the method calling??


P.S. of course I have initialized both method with a Key Pair of public key and private key to the constructor EncryptCBC and DecryptCBC respectively.

A: You must call EncryptCBC.flush()
This is all fine, except for one missing detail. Here is what is happening: Solution 1

After calling the EncryptCBC.encrypt method with the last bit of data, call the flush() method. This causes the internal buffer to be filled with random bits, encrypted and returned. The DecryptCBC object will now return an array containing the plaintext followed by the random data.

Solution 2

Wrap EncryptCBC and DecrytpCBC objects in EncryptStream and DecrytpStream objects respectively. Write the string to the EncryptStream and call flush(). When decrypting, read a string from the DecryptStream and then call drain() to get rid of the random padding.

Note 1

You probably don't want to use RSA to encrypt actual data, but rather to encrypt session keys, preferably by using the EncryptedKeyEx classes in conjunction with the EncryptStream and DecryptStream classes.

Q: Garbage is inserted when I call the flush() method on EncryptStream or EncryptMode. How do I get rid of it?

A: Live with it, use another mode or use DecryptStream.drain().

This happend when you use the ECB or CBC modes, which need a whole multiple of blocks to pass to the encryption key. The size of the block depends on the key used and is returned by the CipherKey.plainBlockSize() method.

If less than a whole multiple of blocks has been sent to the EncryptECB or EncryptCBC object when flush() is called, random data will be appended to make certain attacks on the key more difficult.

Solution 1

Use the CFB or OFB modes, which encrypt a byte at a time. However, CFB is slow, and OFB has not been shown to be as secure as f.ex. CBC. However, it has not been shown to be weak either.

Solution 2

Call DecryptStream.drain() when decrypting, at points in the plaintext where the EncryptStream.flush() was called when encrypting. This requires you to call flush() only at well defined points in the data stream.

Q: How do I encrypt passwords with logi.crypto?

A: Use the Fingerprint.create() method.

Normally, passwords are not encrypted, but hashed. Hashing can be thought of as one-way encryption; there is no key to get back the original password if you know the hashed password.

In logi.crypto this could be done with:

  String password = getPassword();
  Fingerprint fp = Fingerprint.create(password,"SHA1");      

In the above, "SHA1" is the name of the hash-function used. It can be replaced with "MD5" and possibly others will be added in the future.

Please see the next question.

Q: How do I authenticate users?

A: Use the QRAuth classes or generate RSA keys from the password

In many authentication systems the user types in a password which is sent to the server. The server hashes the password and compares the hash to the value stored in a database. There are serious problems with this protocol!

The password could be captured on the network connecting the client and the server. This can be alleviated by sending the password encrypted, for example through an CipherStreamClient initialized with a DHKeyExClient.

The other problem is that the user has no guarantee that he is talking to the correct server and might be giving his password away to the wrong entity.

Solution 1

A better way is to create a pair of CipherStreamClient and CipherStreamServer objects, and execute the appropriate QRAuthClient and QRAuthServer objects on them. This authenticates the client to the server and the server to the client without ever sending the secret to the other.

The QRAuth objects must be initialized with a secret CipherKey object. This could be created by hashing a password and passing the bytes of the hash to the constructor for the CipherKey.

Solution 2

Another way, but more costly in CPU time, is to use the RSAKey.createKeys(userName, password, bitLength) method to generate an RSA key-pair from a username/password pair. This can then be used to authenticate the user. It requires that the public key from the key-pair thus created be known to the server beforehand.

Why does parseCDS() not work when Crypto.fromString() works?
While testing your cryptography package I got the following exception in the code:

KeyPair pair = RSAKey.createKeys(1024);
RSAKey key = (RSAKey)pair.getPublic();

java.lang.NumberFormatException: RSAKey
at java/lang/Long.parseLong (Long.java)
at java/math/BigInteger.<init> (BigInteger.java)
at org/logi/crypto/keys/RSAKey.parseCDS (RSAKey.java:111)

I do not get this exception with:

KeyPair pair = RSAKey.createKeys(1024);
RSAKey key = (RSAKey)pair.getPublic();
RSAKey key2 = (RSAKey)Crypto.fromString(key.toString());

What might be wrong?

A: Don't use parseCDS() or strip the wrapper from the parameters.
You are not actually supposed to be calling the parseCDS functions defined in the various classes. Here is how Crypto.fromString works:

The CDS is "RSAKey(e,n,pub)" with e and n integers represented as hexadecimal strings and pub an actual string. The Crypto.fromString method reads the RSAKey part and sees that this is an RSA key. It uses dynamic class loading and introspection to get a reference to the RSAKey.parseCDS method and calls RSAKey.parseCDS("e,n,pub") This will actually parse the string and return an RSAKey object.

This allows you to add new classes to the library with minimum fuss, even at runtime, and the fromString method will still parse the string representations.

Solution 1

Simply use the Crypto.fromString method in stead of parseCDS.

Solution 2

Strip the "wrapper" from the CDS before calling parseCDS. In the above example, remove the "RSAKey(" from the front, and the ")" from the back.

Q: Why does my program spawn endless OFBThread(A) and OFBThread(B) objects?

A: Call the close() methods

The EncryptOFB, DecryptOFB, EncryptStream, DecryptStream and CipherStream classes all have close() methods which should be called before they are discarded. Amongst other things, they will terminate the threads used for pre-calculating the OFB key-streams.

Homepage | Download | Payment ] [ Logi Ragnarsson | Send Mail ]
General info | Status & Plans | FAQ | Commercial License | Class docs ]