Java Password Encryption

I am trying to learn how to do encryption based on a passphrase using Java. I find some examples on the Internet, but not one (yet) on Stack Overflow. The examples explain me a bit, especially regarding the choice of algorithm. There seems to be a lot of lines around to say which algorithms to use, but little documentation on where the lines came from and what they mean. And it looks like different algorithms may require different implementations of the KeySpec class, so I'm not sure which algorithms the PBEKeySpec class I'm looking at can use. In addition, all the examples seem a bit outdated, many of which require you to get an old cryptography package that was not part of the JDK or even a third-party implementation before.

Can someone provide a simple introduction to what I need to do to implement encryption (String data, string phrase) and decryption (byte [] data, string phrase)?

+6
java encryption passphrase
source share
7 answers

I will be careful in providing or accepting security tips related to the forum ... Specifications are quite complex and often quickly become outdated.

Having said that, I think it's a good reference version of Sun Java Cryptography Architecture (JCA) . Check out the accompanying example illustrating password-based encryption (PBE).

Btw, the standard JRE provides only a few options out of the box for PBE (one of them is “PBEWithMD5AndDES”). For more choices, you will need a “strong encryption package” or some third-party provider, such as Bouncy Castle . Another alternative would be to implement your own PBE using the hash and encryption algorithms presented in the JRE. You can implement PBE with SHA-256 and AES-128 in this way ( examples of encryption / decryption methods ).

In short, the encryption method for PBE may include the following steps:

  • Get the password and clear it from the user and convert them to byte arrays.
  • Create a safe random salt .
  • Attach the salt to the password and calculate its cryptographic hash . Repeat this many times.
  • Encrypt plaintext with the resulting hash as an initialization vector and / or secret key .
  • Save the salt and the resulting ciphertext.
+11
source share

Use RFC2898 to generate keys from passwords. This is not part of the JRE or JCE, as far as I know, but it is included in J2EE servers such as JBoss , Oracle, and WebSphere . It is also included in the .NET base class library ( Rfc2898DeriveBytes ).

There are some LGPL implementations in Java, but with a quick look this one looks a bit more complicated. There is also a good version of javascript . (I produced a modified version of this and packaged it as a component of Windows Script

Not having a good implementation with the appropriate license, I packed some code from Mattias Gartner. This is the whole code. Short, simple, clear. It is licensed under the MS Public License .

// PBKDF2.java // ------------------------------------------------------------------ // // RFC2898 PBKDF2 in Java. The RFC2898 defines a standard algorithm for // deriving key bytes from a text password. This is sometimes // abbreviated "PBKDF2", for Password-based key derivation function #2. // // There no RFC2898-compliant PBKDF2 function in the JRE, as far as I // know, but it is available in many J2EE runtimes, including those from // JBoss, IBM, and Oracle. // // It fairly simple to implement, so here it is. // // Created Sun Aug 09 01:06:57 2009 // // last saved: // Time-stamp: <2009-August-09 02:19:50> // ------------------------------------------------------------------ // // code thanks to Matthias Gartner // // ------------------------------------------------------------------ package cheeso.examples; import java.security.NoSuchAlgorithmException; import java.security.InvalidKeyException; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; public class PBKDF2 { public static byte[] deriveKey( byte[] password, byte[] salt, int iterationCount, int dkLen ) throws java.security.NoSuchAlgorithmException, java.security.InvalidKeyException { SecretKeySpec keyspec = new SecretKeySpec( password, "HmacSHA1" ); Mac prf = Mac.getInstance( "HmacSHA1" ); prf.init( keyspec ); // Note: hLen, dkLen, l, r, T, F, etc. are horrible names for // variables and functions in this day and age, but they // reflect the terse symbols used in RFC 2898 to describe // the PBKDF2 algorithm, which improves validation of the // code vs. the RFC. // // dklen is expressed in bytes. (16 for a 128-bit key) int hLen = prf.getMacLength(); // 20 for SHA1 int l = Math.max( dkLen, hLen); // 1 for 128bit (16-byte) keys int r = dkLen - (l-1)*hLen; // 16 for 128bit (16-byte) keys byte T[] = new byte[l * hLen]; int ti_offset = 0; for (int i = 1; i <= l; i++) { F( T, ti_offset, prf, salt, iterationCount, i ); ti_offset += hLen; } if (r < hLen) { // Incomplete last block byte DK[] = new byte[dkLen]; System.arraycopy(T, 0, DK, 0, dkLen); return DK; } return T; } private static void F( byte[] dest, int offset, Mac prf, byte[] S, int c, int blockIndex ) { final int hLen = prf.getMacLength(); byte U_r[] = new byte[ hLen ]; // U0 = S || INT (i); byte U_i[] = new byte[S.length + 4]; System.arraycopy( S, 0, U_i, 0, S.length ); INT( U_i, S.length, blockIndex ); for( int i = 0; i < c; i++ ) { U_i = prf.doFinal( U_i ); xor( U_r, U_i ); } System.arraycopy( U_r, 0, dest, offset, hLen ); } private static void xor( byte[] dest, byte[] src ) { for( int i = 0; i < dest.length; i++ ) { dest[i] ^= src[i]; } } private static void INT( byte[] dest, int offset, int i ) { dest[offset + 0] = (byte) (i / (256 * 256 * 256)); dest[offset + 1] = (byte) (i / (256 * 256)); dest[offset + 2] = (byte) (i / (256)); dest[offset + 3] = (byte) (i); } // ctor private PBKDF2 () {} } 
+4
source share

Cheeso has a very useful answer above, there is a bad performance error.

Line

 int l = Math.max( dkLen, hLen) 

should not accumulate max, but the division ceiling, therefore

 int l = ((dkLen - 1) / hLen) + 1; // >= ceil(dkLen / hLen), == for dkLen =>1 

This will speed up the calculation by 20 times for 16-byte keys.

+3
source share

You need an encryption library that tells you how to set it up.
I really like the material from bouncycastle.org. You can find them as here DES, mentioned in Example 5.1, is one of the ciphers he offers. What this string means will depend on the provider. Essentially you are loading the library.

 Security.addProvider(new BouncyCastleProvider()); 

And then use only JCE interfaces to do whatever you want:

  keyGen = KeyGenerator.getInstance("DES", "BC"); 

Java handles library and interface bindings for you, you don't need to do this. I would be happier to explain more if you have questions. Unfortunately, at the moment I am suffering from the disease “I don’t remember how I recognized it,” so please do not hesitate to ask.

+2
source share

You can use the hashing algorithm (if necessary several times) to get some raw data from the passphrase that you can use as a key (+ initialization vector if the algorithm requires one).

Then you can use this key with any symmetric algorithm, such as 3DES-CBC or AES-CBC (DES is now deprecated).

Depending on your JCE, you may have different algorithms, but AES is probably what you want. However, the choice of algorithm and how to use it is more of a religious problem, and you would not be well advised to try your own or even try to build your own encryption scheme using standard algorithms. You will almost certainly be mistaken if you have not studied it, and perhaps even if you have it.

If security is important to you that you are considering encryption, you should also consider using a security book such as application cryptography, Bruce Schneier, or Ross Anderson's Security Engineering - there are many implementation errors. For example, using a key phrase as a key is not such a big idea in the first place, because it significantly reduces the size of your key.

You can also see the projects that other people have done, there are many in the IETF, for example: http://tools.ietf.org/html/draft-mcgrew-aead-aes-cbc-hmac-sha1-00

+1
source share

If you do not need to decrypt the passphrase, but just create an encryption key based on the password / passphrase, you can implement the PKCS # 5 standard using the JCE Cipher and MessageDigest classes.

0
source share

Convert the string to an array of bytes during encryption. Convert back to string after decryption.

 /** * Creates a cipher for encryption or decryption. * * @param algorithm PBE algorithm like "PBEWithMD5AndDES" or "PBEWithMD5AndTripleDES". * @param mode Encyrption or decyrption. * @param password Password * @param salt Salt usable with algorithm. * @param count Iterations. * @return Ready initialized cipher. * @throws GeneralSecurityException Error creating the cipher. */ private static Cipher createCipher(final String algorithm, final int mode, final char[] password, final byte[] salt, final int count) throws GeneralSecurityException { final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm); final PBEKeySpec keySpec = new PBEKeySpec(password); final SecretKey key = keyFactory.generateSecret(keySpec); final Cipher cipher = Cipher.getInstance(algorithm); final PBEParameterSpec params = new PBEParameterSpec(salt, count); cipher.init(mode, key, params); return cipher; } /** * Encrypts some data based on a password. * @param algorithm PBE algorithm like "PBEWithMD5AndDES" or "PBEWithMD5AndTripleDES" * @param data Data to encrypt * @param password Password * @param salt Salt usable with algorithm * @param count Iterations. * @return Encrypted data. */ public static byte[] encryptPasswordBased(final String algorithm, final byte[] data, final char[] password, final byte[] salt, final int count) { Validate.notNull(algorithm); Validate.notNull(data); Validate.notNull(password); Validate.notNull(salt); try { final Cipher cipher = createCipher(algorithm, Cipher.ENCRYPT_MODE, password, salt, count); return cipher.doFinal(data); } catch (final Exception ex) { throw new RuntimeException("Error encrypting the password!", ex); } } /** * Decrypts some data based on a password. * @param algorithm PBE algorithm like "PBEWithMD5AndDES" or "PBEWithMD5AndTripleDES" * @param encryptedData Data to decrypt * @param password Password * @param salt Salt usable with algorithm * @param count Iterations. * @return Encrypted data. */ public static byte[] decryptPasswordBased(final String algorithm, final byte[] encryptedData, final char[] password, final byte[] salt, final int count) { Validate.notNull(algorithm); Validate.notNull(encryptedData); Validate.notNull(password); Validate.notNull(salt); try { final Cipher cipher = createCipher(algorithm, Cipher.DECRYPT_MODE, password, salt, count); return cipher.doFinal(encryptedData); } catch (final Exception ex) { throw new RuntimeException("Error decrypting the password!", ex); } } 
0
source share

All Articles