mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
Just Keep RSA and AES
This commit is contained in:
@@ -15,7 +15,7 @@ public abstract class AbstractDecrypter implements Decrypter {
|
||||
/**
|
||||
* DES, AES 密钥都有长度限制, 如果不够, 默认使用该字段补长
|
||||
*/
|
||||
protected static final String KEY_PADDING = "FOLLOW YOUR HEART. YOU CAN DO BEST THAN ANY ONE.";
|
||||
public static final String KEY_PADDING = "FOLLOW YOUR HEART. YOU CAN DO BEST THAN ANY ONE.";
|
||||
|
||||
/**
|
||||
* 传入密文, 返回明文
|
||||
|
||||
@@ -36,6 +36,10 @@ public class AesDecrypter extends AbstractDecrypter {
|
||||
}
|
||||
|
||||
protected SecretKeySpec getSpec() {
|
||||
if (this.spec == null) {
|
||||
setKey("");
|
||||
}
|
||||
|
||||
return this.spec;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
package com.alibaba.druid.support.security.decryptor;
|
||||
|
||||
import com.alibaba.druid.pool.DecryptException;
|
||||
import com.alibaba.druid.pool.Decrypter;
|
||||
import com.alibaba.druid.pool.SensitiveParameters;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* 拷贝JBOSS的Blowfish解密
|
||||
* @author Jonas Yang
|
||||
*/
|
||||
public class BlowfishDecrypter implements Decrypter {
|
||||
|
||||
public SensitiveParameters decrypt(SensitiveParameters parameters) throws DecryptException {
|
||||
byte[] kbytes = "jaas is the way".getBytes();
|
||||
SecretKeySpec key = new SecretKeySpec(kbytes, "Blowfish");
|
||||
|
||||
BigInteger n = new BigInteger(parameters.getPassword(), 16);
|
||||
byte[] encoding = n.toByteArray();
|
||||
|
||||
if (encoding.length % 8 != 0) {
|
||||
int length = encoding.length;
|
||||
int newLength = ((length / 8) + 1) * 8;
|
||||
int pad = newLength - length; //number of leading zeros
|
||||
byte[] old = encoding;
|
||||
encoding = new byte[newLength];
|
||||
|
||||
for (int i = old.length - 1; i >= 0; i--) {
|
||||
encoding[i + pad] = old[i];
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance("Blowfish");
|
||||
cipher.init(Cipher.DECRYPT_MODE, key);
|
||||
byte[] decryptedBytes = cipher.doFinal(encoding);
|
||||
|
||||
return new SensitiveParameters(parameters.getUrl(), parameters.getUsername(), new String(decryptedBytes));
|
||||
} catch (Exception e) {
|
||||
throw new DecryptException("Failed to decrypt JDBC password.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
package com.alibaba.druid.support.security.decryptor;
|
||||
|
||||
import com.alibaba.druid.pool.DecryptException;
|
||||
import com.alibaba.druid.pool.SensitiveParameters;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.SecretKeyFactory;
|
||||
import javax.crypto.spec.DESKeySpec;
|
||||
|
||||
/**
|
||||
* DES 解密器
|
||||
*
|
||||
* @author Jonas Yang
|
||||
*/
|
||||
public class DesDecrypter extends AbstractDecrypter {
|
||||
|
||||
private static final int KEY_LENGTH = 24;
|
||||
|
||||
private volatile SecretKey key;
|
||||
|
||||
public SensitiveParameters decrypt(SensitiveParameters parameters) throws DecryptException {
|
||||
SecretKey key = getKey();
|
||||
if (key == null) {
|
||||
throw new DecryptException("No key.");
|
||||
}
|
||||
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance("DES");
|
||||
cipher.init(Cipher.DECRYPT_MODE, this.key);
|
||||
|
||||
String passwordPlainText = decrypt(cipher, parameters.getPassword());
|
||||
|
||||
return new SensitiveParameters(parameters.getUrl(), parameters.getUsername(), passwordPlainText);
|
||||
} catch (Exception e) {
|
||||
throw new DecryptException("Failed to decrypt JDBC parameters", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
if (key == null) {
|
||||
throw new IllegalArgumentException("The key cannot be null");
|
||||
}
|
||||
|
||||
if (key.length() < 24) {
|
||||
key = KEY_PADDING.substring(0, KEY_LENGTH - key.length()) + key;
|
||||
}
|
||||
|
||||
try {
|
||||
byte[] keyBytes = key.getBytes();
|
||||
DESKeySpec spec = new DESKeySpec(keyBytes);
|
||||
|
||||
SecretKeyFactory factory = SecretKeyFactory.getInstance("DES");
|
||||
this.key = factory.generateSecret(spec);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("Cannot get key.", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected SecretKey getKey() {
|
||||
return this.key;
|
||||
}
|
||||
}
|
||||
@@ -22,15 +22,14 @@ import java.security.spec.X509EncodedKeySpec;
|
||||
*/
|
||||
public class RsaDecrypter extends AbstractDecrypter {
|
||||
|
||||
public static Log log = LogFactory.getLog(RsaDecrypter.class);
|
||||
private static Log log = LogFactory.getLog(RsaDecrypter.class);
|
||||
|
||||
private static final String DEFAULT_PUBLIC_KEY_STRING = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKHGwq7q2RmwuRgKxBypQHw0mYu4BQZ3eMsTrdK8E6igRcxsobUC7uT0SoxIjl1WveWniCASejoQtn/BY6hVKWsCAwEAAQ==";
|
||||
|
||||
private volatile PublicKey publicKey;
|
||||
|
||||
public SensitiveParameters decrypt(SensitiveParameters parameters) throws DecryptException {
|
||||
PublicKey publicKey = getPublicKey();
|
||||
if (publicKey == null) {
|
||||
throw new DecryptException("No public Key.");
|
||||
}
|
||||
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance("RSA");
|
||||
@@ -46,6 +45,10 @@ public class RsaDecrypter extends AbstractDecrypter {
|
||||
}
|
||||
|
||||
protected PublicKey getPublicKey() {
|
||||
if (this.publicKey == null) {
|
||||
setPublicKeyString(DEFAULT_PUBLIC_KEY_STRING);
|
||||
}
|
||||
|
||||
return this.publicKey;
|
||||
}
|
||||
|
||||
|
||||
@@ -54,14 +54,10 @@ public abstract class AbstractAction implements Action {
|
||||
protected String readPassword() {
|
||||
char[] keyChars = System.console().readPassword(this.prompt + "请输入密码[长度最大为" + this.maxKeyLength + "字节]: ");
|
||||
if (keyChars == null) {
|
||||
System.err.println("错误: 密码不能为空!");
|
||||
return null;
|
||||
keyChars = new char[0];
|
||||
}
|
||||
|
||||
String keyString = new String(keyChars);
|
||||
if (keyString == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (keyString.length() < this.minKeyLength || keyString.length() > this.maxKeyLength) {
|
||||
System.err.println("错误: 密码长度要大于等于" + this.minKeyLength + ", 小于等于" + this.maxKeyLength + ".");
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.alibaba.druid.support.security.tool;
|
||||
|
||||
import com.alibaba.druid.support.security.decryptor.AbstractDecrypter;
|
||||
|
||||
/**
|
||||
* @author Jonas Yang
|
||||
*/
|
||||
@@ -7,7 +9,7 @@ public interface Action {
|
||||
/**
|
||||
* DES, AES 密钥都有长度限制, 如果不够, 默认使用该字段补长
|
||||
*/
|
||||
public String KEY_PADDING = "FOLLOW YOUR HEART. YOU CAN DO BEST THAN ANY ONE.";
|
||||
public String KEY_PADDING = AbstractDecrypter.KEY_PADDING;
|
||||
|
||||
public String getId();
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import javax.crypto.spec.SecretKeySpec;
|
||||
public class AesAction extends AbstractAction {
|
||||
|
||||
public AesAction() {
|
||||
super(6, 16, "AES");
|
||||
super(0, 16, "AES");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
package com.alibaba.druid.support.security.tool;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* @author Jonas Yang
|
||||
*/
|
||||
public class BlowfishAction implements Action {
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "Blowfish";
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
System.out.println();
|
||||
String plainString = System.console().readLine("[Blowfish]请输入要需要加密的明文: ");
|
||||
if (plainString == null) {
|
||||
System.err.println("输入不能为空.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
String encryptedString = encrypt(plainString);
|
||||
System.out.println("请记住以下的密文, 长度为[" + encryptedString.length() + "].");
|
||||
System.out.println();
|
||||
System.out.println(encryptedString);
|
||||
System.out.println();
|
||||
} catch (Exception e) {
|
||||
System.out.println("加密出错.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private String encrypt(String plainString) throws Exception {
|
||||
byte[] kbytes = "jaas is the way".getBytes();
|
||||
SecretKeySpec key = new SecretKeySpec(kbytes, "Blowfish");
|
||||
|
||||
Cipher cipher = Cipher.getInstance("Blowfish");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key);
|
||||
byte[] encoding = cipher.doFinal(plainString.getBytes());
|
||||
BigInteger n = new BigInteger(encoding);
|
||||
return n.toString(16);
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package com.alibaba.druid.support.security.tool;
|
||||
|
||||
import com.alibaba.druid.util.Base64;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.SecretKeyFactory;
|
||||
import javax.crypto.spec.DESKeySpec;
|
||||
|
||||
/**
|
||||
* @author Jonas Yang
|
||||
*/
|
||||
public class DesAction extends AbstractAction {
|
||||
|
||||
public DesAction() {
|
||||
super(6, 24, "DES");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "DES";
|
||||
}
|
||||
|
||||
public String encrypt(String keyString, String plainString) throws Exception {
|
||||
DESKeySpec spec = new DESKeySpec(keyString.getBytes());
|
||||
|
||||
SecretKeyFactory factory = SecretKeyFactory.getInstance("DES");
|
||||
SecretKey key = factory.generateSecret(spec);
|
||||
|
||||
Cipher cipher = Cipher.getInstance("DES");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key);
|
||||
|
||||
byte[] encryptedBytes = cipher.doFinal(plainString.getBytes());
|
||||
|
||||
return Base64.byteArrayToBase64(encryptedBytes);
|
||||
}
|
||||
}
|
||||
@@ -17,9 +17,7 @@ public class Main {
|
||||
static {
|
||||
int i = 1;
|
||||
help.addAction(Integer.toString(i++), new RsaAction());
|
||||
help.addAction(Integer.toString(i++), new DesAction());
|
||||
help.addAction(Integer.toString(i++), new AesAction());
|
||||
help.addAction(Integer.toString(i++), new BlowfishAction());
|
||||
help.addAction("h", help);
|
||||
help.addAction("q", new QuitAction());
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ import java.security.spec.PKCS8EncodedKeySpec;
|
||||
*/
|
||||
public class RsaAction implements Action {
|
||||
|
||||
private static final String DEFAULT_PRIVATE_KEY_STRING = "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAocbCrurZGbC5GArEHKlAfDSZi7gFBnd4yxOt0rwTqKBFzGyhtQLu5PRKjEiOXVa95aeIIBJ6OhC2f8FjqFUpawIDAQABAkAPejKaBYHrwUqUEEOe8lpnB6lBAsQIUFnQI/vXU4MV+MhIzW0BLVZCiarIQqUXeOhThVWXKFt8GxCykrrUsQ6BAiEA4vMVxEHBovz1di3aozzFvSMdsjTcYRRo82hS5Ru2/OECIQC2fAPoXixVTVY7bNMeuxCP4954ZkXp7fEPDINCjcQDywIgcc8XLkkPcs3Jxk7uYofaXaPbg39wuJpEmzPIxi3k0OECIGubmdpOnin3HuCP/bbjbJLNNoUdGiEmFL5hDI4UdwAdAiEAtcAwbm08bKN7pwwvyqaCBC//VnEWaq39DCzxr+Z2EIk=";
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "RSA";
|
||||
@@ -28,47 +30,31 @@ public class RsaAction implements Action {
|
||||
System.out.println("2. 创建 RSA 密钥");
|
||||
|
||||
String input = System.console().readLine("[RSA]请输入选项: ");
|
||||
if (input == null || input.length() == 0) {
|
||||
System.err.println("不是一个合法的输入.");
|
||||
}
|
||||
|
||||
if ("1".equals(input)) {
|
||||
encrypt();
|
||||
return;
|
||||
}
|
||||
|
||||
if ("2".equals(input)) {
|
||||
} else if ("2".equals(input)) {
|
||||
generateKeys();
|
||||
} else {
|
||||
System.err.println("不是一个合法的输入.");
|
||||
}
|
||||
}
|
||||
|
||||
private void encrypt() {
|
||||
String filePath = System.console().readLine("[RSA]请输入私钥文件路径: ");
|
||||
if (!new File(filePath).exists()) {
|
||||
System.err.println("文件不存在[" + filePath + "]");
|
||||
}
|
||||
String filePath = System.console().readLine("[RSA]请输入私钥文件路径[如果直接回车将使用默认私钥]: ");
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
FileInputStream in = null;
|
||||
try {
|
||||
in = new FileInputStream(filePath);
|
||||
byte[] b = new byte[512/8];
|
||||
int len = 0;
|
||||
while ((len = in.read(b)) != -1) {
|
||||
out.write(b, 0, len);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println("读取文件出错. " + e.getMessage());
|
||||
} finally {
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
byte[] key = null;
|
||||
if (filePath == null || filePath.length() == 0) {
|
||||
key = Base64.base64ToByteArray(DEFAULT_PRIVATE_KEY_STRING);
|
||||
} else {
|
||||
try {
|
||||
key = getPrivateKeyFromFile(filePath);
|
||||
} catch (Exception e) {
|
||||
System.err.println("读取文件出错. " + e.getMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
byte[] key = out.toByteArray();
|
||||
String plainString = System.console().readLine("[RSA]请输入要需要加密的明文: ");
|
||||
|
||||
try {
|
||||
@@ -91,7 +77,46 @@ public class RsaAction implements Action {
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] getPrivateKeyFromFile(String filePath) throws IOException {
|
||||
if (!new File(filePath).exists()) {
|
||||
System.err.println("文件不存在[" + filePath + "]");
|
||||
}
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
FileInputStream in = null;
|
||||
try {
|
||||
in = new FileInputStream(filePath);
|
||||
byte[] b = new byte[512/8];
|
||||
int len = 0;
|
||||
while ((len = in.read(b)) != -1) {
|
||||
out.write(b, 0, len);
|
||||
}
|
||||
} finally {
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
private void generateKeys() {
|
||||
System.out.println();
|
||||
System.out.println("[RSA]请选择密钥长度: \n1. 512 \n2. 1024 \n3. 2048");
|
||||
String keySizeString = System.console().readLine("[RSA]请输入选项: ");
|
||||
|
||||
int keySize = 512;
|
||||
if ("1".equals(keySizeString) || "2".equals(keySizeString) || "3".equals(keySizeString)) {
|
||||
int power = (Integer.valueOf(keySizeString) - 1);
|
||||
keySize = keySize << power;
|
||||
} else {
|
||||
System.err.println("不是一个合法的输入.");
|
||||
return;
|
||||
}
|
||||
|
||||
String input = System.console().readLine("[RSA]请输入输出路径: ");
|
||||
if (input == null) {
|
||||
input = "";
|
||||
@@ -99,7 +124,7 @@ public class RsaAction implements Action {
|
||||
|
||||
try {
|
||||
KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
|
||||
gen.initialize(1024, new SecureRandom());
|
||||
gen.initialize(keySize, new SecureRandom());
|
||||
KeyPair pair = gen.generateKeyPair();
|
||||
|
||||
String privateKeyPath = input + ".private.key";
|
||||
@@ -128,4 +153,23 @@ public class RsaAction implements Action {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
FileInputStream in = null;
|
||||
try {
|
||||
in = new FileInputStream("/Users/yangkingsel/druid.public.key");
|
||||
byte[] buf = new byte[512/8];
|
||||
int len;
|
||||
while ((len = in.read(buf)) != -1) {
|
||||
out.write(buf, 0, len);
|
||||
}
|
||||
|
||||
System.out.println(Base64.byteArrayToBase64(out.toByteArray()));
|
||||
} finally {
|
||||
if (in != null) {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
package com.alibaba.druid.bvt.support.security;
|
||||
|
||||
import com.alibaba.druid.support.security.decryptor.AesDecrypterTest;
|
||||
import com.alibaba.druid.support.security.decryptor.BlowfishDecrypterTest;
|
||||
import com.alibaba.druid.support.security.decryptor.DesDecrypterTest;
|
||||
import com.alibaba.druid.support.security.decryptor.RsaDecrypterTest;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Suite;
|
||||
@@ -13,9 +11,7 @@ import org.junit.runners.Suite;
|
||||
@RunWith(Suite.class)
|
||||
@Suite.SuiteClasses({
|
||||
AesDecrypterTest.class,
|
||||
DesDecrypterTest.class,
|
||||
RsaDecrypterTest.class,
|
||||
BlowfishDecrypterTest.class
|
||||
RsaDecrypterTest.class
|
||||
})
|
||||
public class DecrypterTestSuite {
|
||||
}
|
||||
|
||||
@@ -18,4 +18,12 @@ public class AesDecrypterTest {
|
||||
|
||||
Assert.assertEquals("It is not same.", "xiaoyu", parameters.getPassword());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDecryptWithEmptyKey() throws DecryptException {
|
||||
AesDecrypter decrypter = new AesDecrypter();
|
||||
SensitiveParameters parameters = decrypter.decrypt(new SensitiveParameters("", "", "AzgdbVU3SIK6A8+0qg+Btg=="));
|
||||
|
||||
Assert.assertEquals("It is not same.", "xiaoyu", parameters.getPassword());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
package com.alibaba.druid.support.security.decryptor;
|
||||
|
||||
import com.alibaba.druid.pool.DecryptException;
|
||||
import com.alibaba.druid.pool.SensitiveParameters;
|
||||
import junit.framework.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author Jonas Yang
|
||||
*/
|
||||
public class BlowfishDecrypterTest {
|
||||
|
||||
@Test
|
||||
public void testDecrypt() throws DecryptException {
|
||||
BlowfishDecrypter decrypter = new BlowfishDecrypter();
|
||||
SensitiveParameters parameters = decrypter.decrypt(new SensitiveParameters("", "", "64c5fd2979a86168"));
|
||||
|
||||
Assert.assertEquals("It is not same.", "123456", parameters.getPassword());
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package com.alibaba.druid.support.security.decryptor;
|
||||
|
||||
import com.alibaba.druid.pool.DecryptException;
|
||||
import com.alibaba.druid.pool.SensitiveParameters;
|
||||
import junit.framework.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author Jonas Yang
|
||||
*/
|
||||
public class DesDecrypterTest {
|
||||
|
||||
@Test
|
||||
public void testDecrypt() throws DecryptException {
|
||||
DesDecrypter decrypter = new DesDecrypter();
|
||||
decrypter.setKey("123456");
|
||||
SensitiveParameters parameters = decrypter.decrypt(new SensitiveParameters("", "", "rIsr38vJDyQ="));
|
||||
|
||||
Assert.assertEquals("It is not same", parameters.getPassword(), "xiaoyu");
|
||||
}
|
||||
}
|
||||
@@ -61,4 +61,12 @@ public class RsaDecrypterTest {
|
||||
Assert.assertEquals("It is not same.", "xiaoyu", parameters.getPassword());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDecryptWithEmptyKey() throws DecryptException {
|
||||
RsaDecrypter decrypter = new RsaDecrypter();
|
||||
SensitiveParameters parameters = decrypter.decrypt(new SensitiveParameters("", "", "OJfUm6WCHi7EuXqE6aEc+Po2xFrAGBeSNy8O2jWhV2FTG8/5kbRRr2rjNKhptlevm/03Y0048P7h88gdUOXAYg=="));
|
||||
|
||||
Assert.assertEquals("It is not same.", "xiaoyu", parameters.getPassword());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user