From 50d439703e9947b155314403714615c846aa13d9 Mon Sep 17 00:00:00 2001 From: Duncan Mac-Vicar P Date: Tue, 7 Jun 2016 23:57:16 +0200 Subject: [PATCH 1/2] add test for PwdUtil encrypt/decrypt --- .../java/net/ocheyedan/ply/PwdUtilTest.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 ply-util/src/test/java/net/ocheyedan/ply/PwdUtilTest.java diff --git a/ply-util/src/test/java/net/ocheyedan/ply/PwdUtilTest.java b/ply-util/src/test/java/net/ocheyedan/ply/PwdUtilTest.java new file mode 100644 index 0000000..aa0c630 --- /dev/null +++ b/ply-util/src/test/java/net/ocheyedan/ply/PwdUtilTest.java @@ -0,0 +1,21 @@ +package net.ocheyedan.ply; + +import org.junit.Test; +import java.util.UUID; + +import static junit.framework.Assert.assertEquals; +import static org.junit.Assert.*; +import static org.hamcrest.CoreMatchers.*; + +public class PwdUtilTest { + + @Test + public void testSimpleEncryption() { + String text = UUID.randomUUID().toString(); + String enc = PwdUtil.encrypt(text); + assertThat(text, not(equalTo(enc))); + String dec = PwdUtil.decrypt(enc); + assertEquals(text, dec); + } + +} \ No newline at end of file From 0883b5322a4c1e92ea0920817724472292b96de9 Mon Sep 17 00:00:00 2001 From: Duncan Mac-Vicar P Date: Wed, 8 Jun 2016 01:20:17 +0200 Subject: [PATCH 2/2] Remove dependency on Base64 from jasypt We can use sun.misc.BASE64* as it is already used in net.ocheyedan.ply.dep.BasicAuth. In the future should look for a Apache licensed file and copy it into the tree as sun.misc.* is not public API. --- .../main/java/net/ocheyedan/ply/PwdUtil.java | 65 +++++++++++++++---- 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/ply-util/src/main/java/net/ocheyedan/ply/PwdUtil.java b/ply-util/src/main/java/net/ocheyedan/ply/PwdUtil.java index 2dedb6a..dac7793 100644 --- a/ply-util/src/main/java/net/ocheyedan/ply/PwdUtil.java +++ b/ply-util/src/main/java/net/ocheyedan/ply/PwdUtil.java @@ -1,12 +1,24 @@ package net.ocheyedan.ply; -import org.jasypt.contrib.org.apache.commons.codec_1_3.binary.Base64; -import org.jasypt.util.text.BasicTextEncryptor; - import java.nio.charset.Charset; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; +import sun.misc.BASE64Encoder; +import sun.misc.BASE64Decoder; + +import javax.crypto.Cipher; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.PBEParameterSpec; +import java.security.SecureRandom; +import javax.crypto.SecretKeyFactory; +import javax.crypto.SecretKey; +import java.util.Random; +import java.io.ByteArrayOutputStream; +import java.util.Arrays; +import java.lang.RuntimeException; + + /** * User: blangel * Date: 1/9/13 @@ -37,6 +49,9 @@ public String getLine() { private static final Request REQUEST = new Request(); + private static final Random RANDOM = new SecureRandom(); + private static final char[] PASSWORD = "P1y$".toCharArray(); + /** * Parses {@code line} and if it starts with {@link #PWD_REQUEST_TOKEN} then strips the prefix and returns * a {@link Request} object with the stripped line and value of true for {@link Request#pwd}, otherwise, @@ -66,11 +81,25 @@ public static Request isPwdRequest(String line) { * @return the encrypted value */ public static String encrypt(String value) { - BasicTextEncryptor textEncryptor = new BasicTextEncryptor(); - textEncryptor.setPassword("P1y$"); - String encrypted = textEncryptor.encrypt(value); - byte[] base64 = Base64.encodeBase64(encrypted.getBytes(CHARSET)); - return new String(base64, CHARSET); + byte[] salt = new byte[8]; + RANDOM.nextBytes(salt); + try { + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES"); + SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PASSWORD)); + Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES"); + pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(salt, 20)); + byte[] enc = pbeCipher.doFinal(value.getBytes(CHARSET)); + + ByteArrayOutputStream saltPlusEnc = new ByteArrayOutputStream(); + saltPlusEnc.write(salt); + saltPlusEnc.write(enc); + + BASE64Encoder encoder = new sun.misc.BASE64Encoder(); + return encoder.encode(saltPlusEnc.toByteArray()); + } + catch (Exception e) { + throw new RuntimeException("Encryption failed: " + e.getMessage()); + } } /** @@ -80,10 +109,22 @@ public static String encrypt(String value) { * @return the decrypted value */ public static String decrypt(String value) { - byte[] decoded = Base64.decodeBase64(value.getBytes(CHARSET)); - BasicTextEncryptor textEncryptor = new BasicTextEncryptor(); - textEncryptor.setPassword("P1y$"); - return textEncryptor.decrypt(new String(decoded, CHARSET)); + try { + BASE64Decoder decoder = new sun.misc.BASE64Decoder(); + + byte[] saltPlusEnc = decoder.decodeBuffer(value); + byte[] salt = Arrays.copyOfRange(saltPlusEnc, 0, 8); + byte[] enc = Arrays.copyOfRange(saltPlusEnc, 8, saltPlusEnc.length); + + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES"); + SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PASSWORD)); + Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES"); + pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(salt, 20)); + return new String(pbeCipher.doFinal(enc), "UTF-8"); + } + catch (Exception e) { + throw new RuntimeException("Decryption failed: " + e.getMessage()); + } } private PwdUtil() { }