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.
On Tue, Feb 08, 2000 at 03:39:51AM +0800, Simon Liu Sai Man wrote:A: You must call EncryptCBC.flush()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??
Thanks
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.
This is all fine, except for one missing detail. Here is what is happening:Solution 1
- You initialize the EncryptCBC object with an RSA key. It looks at the key and decides that it needs a block-size of 128 bytes. That presumably means that you are using a 1024 bit key-pair.
- You send it a string about a cat? Anyway, you send it some data to encrypt and because this is the first bit of data it gets, it creates an IV (initialization vector) which is one block of random bits. The IV is there to make sure that if you encrypt the same data twice, the ciphertext looks different.
However, the 9 bytes you want to encrypt are not enough to fill an entire block, so they are stored and will be encrypted when the block fills up.
What you get is the IV and *no ciphertext*.- The DecryptCBC gets your array of 128 bytes of IV and initializes itself with that. It sees no cicphertext following, so it returns an empty array as it should.
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.
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.
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.
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.
While testing your cryptography package I got the following exception in the code:A: Don't use parseCDS() or strip the wrapper from the parameters.KeyPair pair = RSAKey.createKeys(1024);
RSAKey key = (RSAKey)pair.getPublic();
RSAKey.parseCDS(key.toString());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?
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 ]