Quantcast
Channel: CodeSection,代码区,网络安全 - CodeSec
Viewing all articles
Browse latest Browse all 12749

Druid数据连接池字符串解密

$
0
0
Driud是什么

Druid是阿里巴巴开源平台上的一个项目,整个项目由数据库连接池、插件框架和SQL解析器组成。该项目主要是为了扩展JDBC的一些限制,可以让程序员实现一些特殊的需求,比如向密钥服务请求凭证、统计SQL信息、SQL性能收集、SQL注入检查、SQL翻译等,程序员可以通过定制来实现自己需要的功能。

Druid解密方式

Druid数据库加密算法采用的是RSA非对称加解密,并且秘钥的配置支持多种方式:

远程加载秘钥文件 读取本地秘钥文件 使用系统属性加载秘钥 使用默认秘钥加解密 远程加载

在Spring中配置像这样:

1

2

3

4

<bean id=”dataSource” class=”com.alibaba.druid.pool.DruidDataSource” init-method=”init” destroy-method=”close”>

<property name=”filters” value=”config” />

<property name=”connectionProperties” value=”config.file=http://remote:8080/remote.propreties; />

</bean>

从远程服务器中加载包含秘钥的remote.propreties

####读取本地秘钥

读取本地配置文件

1

2

3

4

5

<bean id=”dataSource” class=”com.alibaba.druid.pool.DruidDataSource”

init-method=”init” destroy-method=”close”>

<property name=”filters” value=”config” />

<property name=”connectionProperties” value=”config.file=file:///home/admin/druid-pool.properties” />

</bean>

系统属性中获取秘钥

获取解密的代码如下:

1

2

public static final String SYS_PROP_CONFIG_KEY = “druid.config.decrypt.key”;

key = System.getProperty(SYS_PROP_CONFIG_KEY);

如果前两种方式都未能找到解密的KEY,那么会在java系统熟悉中去获取秘钥。

默认秘钥

如果上述所有方法都无法获取秘钥,那么程序将使用默认秘钥去加解密。

解密

找到秘钥后就可以使用下列代码进行解密,不过大多数开发都是采用默认秘钥去加密字符串,实质上并没有什么卵用。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

package org.iswin.csv;

import java.io.ByteArrayOutputStream;

import java.io.FileInputStream;

import java.io.IOException;

import java.security.InvalidKeyException;

import java.security.Key;

import java.security.KeyFactory;

import java.security.KeyPair;

import java.security.KeyPairGenerator;

import java.security.NoSuchAlgorithmException;

import java.security.PrivateKey;

import java.security.PublicKey;

import java.security.SecureRandom;

import java.security.cert.Certificate;

import java.security.cert.CertificateFactory;

import java.security.interfaces.RSAPrivateKey;

import java.security.interfaces.RSAPublicKey;

import java.security.spec.PKCS8EncodedKeySpec;

import java.security.spec.RSAPrivateKeySpec;

import java.security.spec.RSAPublicKeySpec;

import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;

public class ConfigTools {

private static final String DEFAULT_PRIVATE_KEY_STRING = “MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAocbCrurZGbC5GArEHKlAfDSZi7gFBnd4yxOt0rwTqKBFzGyhtQLu5PRKjEiOXVa95aeIIBJ6OhC2f8FjqFUpawIDAQABAkAPejKaBYHrwUqUEEOe8lpnB6lBAsQIUFnQI/vXU4MV+MhIzW0BLVZCiarIQqUXeOhThVWXKFt8GxCykrrUsQ6BAiEA4vMVxEHBovz1di3aozzFvSMdsjTcYRRo82hS5Ru2/OECIQC2fAPoXixVTVY7bNMeuxCP4954ZkXp7fEPDINCjcQDywIgcc8XLkkPcs3Jxk7uYofaXaPbg39wuJpEmzPIxi3k0OECIGubmdpOnin3HuCP/bbjbJLNNoUdGiEmFL5hDI4UdwAdAiEAtcAwbm08bKN7pwwvyqaCBC//VnEWaq39DCzxr+Z2EIk=”;

public static final String DEFAULT_PUBLIC_KEY_STRING = “MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKHGwq7q2RmwuRgKxBypQHw0mYu4BQZ3eMsTrdK8E6igRcxsobUC7uT0SoxIjl1WveWniCASejoQtn/BY6hVKWsCAwEAAQ==”;

public static void main(String[] args) throws Exception {

System.out.println(decrypt(“MIqXaohFx7rvzJv5ZAb6ZvPPFDFMxL50yiAhks2Qg9822gi/X4to4UHJb10zCIN89B0n95nZWJTYtJ2SmZ0RTQ==”));

}

public static String decrypt(String cipherText) throws Exception {

return decrypt((String) null, cipherText);

}

public static String decrypt(String publicKeyText, String cipherText)

throws Exception {

PublicKey publicKey = getPublicKey(publicKeyText);

return decrypt(publicKey, cipherText);

}

public static PublicKey getPublicKeyByX509(String x509File) {

if (x509File == null || x509File.length() == 0) {

return ConfigTools.getPublicKey(null);

}

FileInputStream in = null;

try {

in = new FileInputStream(x509File);

CertificateFactory factory = CertificateFactory

.getInstance(“X.509”);

Certificate cer = factory.generateCertificate(in);

return cer.getPublicKey();

} catch (Exception e) {

throw new IllegalArgumentException(“Failed to get public key”, e);

} finally {

try {

in.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

public static PublicKey getPublicKey(String publicKeyText) {

if (publicKeyText == null || publicKeyText.length() == 0) {

publicKeyText = ConfigTools.DEFAULT_PUBLIC_KEY_STRING;

}

try {

byte[] publicKeyBytes = Base64.base64ToByteArray(publicKeyText);

X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(

publicKeyBytes);

KeyFactory keyFactory = KeyFactory.getInstance(“RSA”);

return keyFactory.generatePublic(x509KeySpec);

} catch (Exception e) {

throw new IllegalArgumentException(“Failed to get public key”, e);

}

}

public static PublicKey getPublicKeyByPublicKeyFile(String publicKeyFile) {

if (publicKeyFile == null || publicKeyFile.length() == 0) {

return ConfigTools.getPublicKey(null);

}

FileInputStream in = null;

try {

in = new FileInputStream(publicKeyFile);

ByteArrayOutputStream out = new ByteArrayOutputStream();

int len = 0;

byte[] b = new byte[512 / 8];

while ((len = in.read(b)) != -1) {

out.write(b, 0, len);

}

byte[] publicKeyBytes = out.toByteArray();

X509EncodedKeySpec spec = new X509EncodedKeySpec(publicKeyBytes);

KeyFactory factory = KeyFactory.getInstance(“RSA”);

return factory.generatePublic(spec);

} catch (Exception e) {

throw new IllegalArgumentException(“Failed to get public key”, e);

} finally {

try {

in.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

public static String decrypt(PublicKey publicKey, String cipherText)

throws Exception {

Cipher cipher = Cipher.getInstance(“RSA”);

try {

cipher.init(Cipher.DECRYPT_MODE, publicKey);

} catch (InvalidKeyException e) {

// 因为 IBM JDK 不支持私钥加密, 公钥解密, 所以要反转公私钥

// 也就是说对于解密, 可以通过公钥的参数伪造一个私钥对象欺骗 IBM JDK

RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;

RSAPrivateKeySpec spec = new RSAPrivateKeySpec(rsaPublicKey.getModulus(), rsaPublicKey.getPublicExponent());

Key fakePrivateKey = KeyFactory.getInstance(“RSA”).generatePrivate(spec);

cipher = Cipher.getInstance(“RSA”); //It is a stateful object. so we need to get new one.

cipher.init(Cipher.DECRYPT_MODE, fakePrivateKey);

}

if (cipherText == null || cipherText.length() == 0) {

return cipherText;

}

byte[] cipherBytes = Base64.base64ToByteArray(cipherText); byte[] plainBytes = cipher.doFinal(cipherBytes);

return new String(plainBytes);

}

public static String encrypt(String plainText) throws Exception {

return encrypt((String) null, plainText);

}

public static String encrypt(String key, String plainText) throws Exception {

if (key == null) {

key = DEFAULT_PRIVATE_KEY_STRING;

}

byte[] keyBytes = Base64.base64ToByteArray(key);

return encrypt(keyBytes, plainText);

}

public static String encrypt(byte[] keyBytes, String plainText)

throws Exception {

PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);

KeyFactory factory = KeyFactory.getInstance(“RSA”);

PrivateKey privateKey = factory.generatePrivate(spec);

Cipher cipher = Cipher.getInstance(“RSA”);

try {

cipher.init(Cipher.ENCRYPT_MODE, privateKey);

} catch (InvalidKeyException e) {

//For IBM JDK, 原因请看解密方法中的说明

RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) privateKey;

RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(rsaPrivateKey.getModulus(), rsaPrivateKey.getPrivateExponent());

Key fakePublicKey = KeyFactory.getInstance(“RSA”).generatePublic(publicKeySpec);

cipher = Cipher.getInstance(“RSA”);

cipher.init(Cipher.ENCRYPT_MODE, fakePublicKey);

}

byte[] encryptedBytes = cipher.doFinal(plainText.getBytes(“UTF-8”));

String encryptedString = Base64.byteArrayToBase64(encryptedBytes);

return encryptedString;

}

public static byte[][] genKeyPairBytes(int keySize)

throws NoSuchAlgorithmException {

byte[][] keyPairBytes = new byte[2][];

KeyPairGenerator gen = KeyPairGenerator.getInstance(“RSA”);

gen.initialize(keySize, new SecureRandom());

KeyPair pair = gen.generateKeyPair();

keyPairBytes[0] = pair.getPrivate().getEncoded(); keyPairBytes[1] = pair.getPublic().getEncoded();

return keyPairBytes;

}

public static String[] genKeyPair(int keySize)

throws NoSuchAlgorithmException {

byte[][] keyPairBytes = genKeyPairBytes(keySize); String[] keyPairs = new String[2]; keyPairs[0] = Base64.byteArrayToBase64(keyPairBytes[0]); keyPairs[1] = Base64.byteArrayToBase64(keyPairBytes[1]);

return keyPairs;

}

}

BASE64工具

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

package org.iswin.csv;

/**

* Static methods for translating Base64 encoded strings to byte arrays and vice-versa.

*

* @author Josh Bloch

* @version %I%, %G%

* @see Preferences

* @since 1.4

*/

public class Base64 {

/**

* Translates the specified byte array into a Base64 string as per Preferences.put(byte[]).

*/

public static String byteArrayToBase64(byte[] a) {

return byteArrayToBase64(a, false);

}

/**

* Translates the specified byte array into an “alternate representation” Base64 string. This non-standard variant

* uses an alphabet that does not contain the uppercase alphabetic characters, which makes it suitable for use in

* situations where case-folding occurs.

*/

public static String byteArrayToAltBase64(byte[] a) {

return byteArrayToBase64(a, true);

}

private static String byteArrayToBase64(byte[] a, boolean alternate) {

int aLen = a.length;

int numFullGroups = aLen / 3;

int numBytesInPartialGroup = aLen 3 * numFullGroups;

int resultLen = 4 * ((aLen + 2) / 3);

StringBuilder result = new StringBuilder(resultLen);

char[] intToAlpha = (alternate ? intToAltBase64 : intToBase64);

// Translate all full groups from byte array elements to Base64

int inCursor = 0;

for (int i = 0; i < numFullGroups; i++) {

int byte0 = a[inCursor++] & 0xff; int byte1 = a[inCursor++] & 0xff; int byte2 = a[inCursor++] & 0xff; result.append(intToAlpha[byte0 >> 2]); result.append(intToAlpha[(byte0 << 4) & 0x3f | (byte1 >> 4)]); result.append(intToAlpha[(byte1 << 2) & 0x3f | (byte2 >> 6)]); result.append(intToAlpha[byte2 & 0x3f]);

}

// Translate partial group if present

if (numBytesInPartialGroup != 0) {

int byte0 = a[inCursor++] & 0xff; result.append(intToAlpha[byte0 >> 2]);

if (numBytesInPartialGroup == 1) {

result.append(intToAlpha[(byte0 << 4) & 0x3f]);

result.append(“==”);

} else {

// assert numBytesInPartialGroup == 2;

int byte1 = a[inCursor++] & 0xff; result.append(intToAlpha[(byte0 << 4) & 0x3f | (byte1 >> 4)]); result.append(intToAlpha[(byte1 << 2) & 0x3f]);

result.append(‘=’);

}

}

// assert inCursor == a.length;

// assert result.length() == resultLen;

return result.toString();

}

/**

* This array is a lookup table that translates 6-bit positive integer index values into their “Base64 Alphabet”

* equivalents as specified in Table 1 of RFC 2045.

*/

private static final char intToBase64[] = { ‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’, ‘G’, ‘H’, ‘I’, ‘J’, ‘K’, ‘L’, ‘M’,

‘N’, ‘O’, ‘P’, ‘Q’, ‘R’, ‘S’, ‘T’, ‘U’, ‘V’, ‘W’, ‘X’, ‘Y’, ‘Z’, ‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’, ‘g’, ‘h’,

‘i’, ‘j’, ‘k’, ‘l’, ‘m’, ‘n’, ‘o’, ‘p’, ‘q’, ‘r’, ‘s’, ‘t’, ‘u’, ‘v’, ‘w’, ‘x’, ‘y’, ‘z’, ‘0’, ‘1’, ‘2’,

‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’, ‘+’, ‘/’ };

/**

* This array is a lookup table that translates 6-bit positive integer index values into their

* “Alternate Base64 Alphabet” equivalents. This is NOT the real Base64 Alphabet as per in Table 1 of RFC 2045. This

* alternate alphabet does not use the capital letters. It is designed for use in environments where “case folding”

* occurs.

*/

private static final char intToAltBase64[] = { ‘!’, ‘”‘, ‘#’, ‘$’, ‘%’, ‘&’, ‘/”, ‘(‘, ‘)’, ‘,’, ‘-‘, ‘.’, ‘:’, ‘;’, ‘<‘, ‘>’, ‘@’, ‘[‘, ‘]’, ‘^’, ‘`’, ‘_’, ‘{‘, ‘|’, ‘}’, ‘~’, ‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’, ‘g’, ‘h’,

‘i’, ‘j’, ‘k’, ‘l’, ‘m’, ‘n’, ‘o’, ‘p’, ‘q’, ‘r’, ‘s’, ‘t’, ‘u’, ‘v’, ‘w’, ‘x’, ‘y’, ‘z’, ‘0’, ‘1’, ‘2’,

‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’, ‘+’, ‘?’ };

/**

* Translates the specified Base64 string (as per Preferences.get(byte[])) into a byte array.

*

* @throw IllegalArgumentException if <tt>s</tt> is not a valid Base64 string.

*/

public static byte[] base64ToByteArray(String s) {

return base64ToByteArray(s, false);

}

/**

* Translates the specified “alternate representation” Base64 string into a byte array.

*

* @throw IllegalArgumentException or ArrayOutOfBoundsException if <tt>s</tt> is not a valid alternate

* representation Base64 string.

*/

public static byte[] altBase64ToByteArray(String s) {

return base64ToByteArray(s, true);

}

private static byte[] base64ToByteArray(String s, boolean alternate) { byte[] alphaToInt = (alternate ? altBase64ToInt : base64ToInt);

int sLen = s.length();

int numGroups = sLen / 4;

if (4 * numGroups != sLen) {

throw new IllegalArgumentException(“String length must be a multiple of four.”);

}

int missingBytesInLastGroup = 0;

int numFullGroups = numGroups;

if (sLen != 0) {

if (s.charAt(sLen 1) == ‘=’) {

missingBytesInLastGroup++;

numFullGroups ;

}

if (s.charAt(sLen 2) == ‘=’) {

missingBytesInLastGroup++;

}

}

byte[] result = new byte[3 * numGroups missingBytesInLastGroup];

// Translate all full groups from base64 to byte array elements

int inCursor = 0, outCursor = 0;

for (int i = 0; i < numFullGroups; i++) {

int ch0 = base64toInt(s.charAt(inCursor++), alphaToInt);

int ch1 = base64toInt(s.charAt(inCursor++), alphaToInt);

int ch2 = base64toInt(s.charAt(inCursor++), alphaToInt);

int ch3 = base64toInt(s.charAt(inCursor++), alphaToInt);

result[outCursor++] = (byte) ((ch0 << 2) | (ch1 >> 4)); result[outCursor++] = (byte) ((ch1 << 4) | (ch2 >> 2)); result[outCursor++] = (byte) ((ch2 << 6) | ch3);

}

// Translate partial group, if present

if (missingBytesInLastGroup != 0) {

int ch0 = base64toInt(s.charAt(inCursor++), alphaToInt);

int ch1 = base64toInt(s.charAt(inCursor++), alphaToInt);

result[outCursor++] = (byte) ((ch0 << 2) | (ch1 >> 4));

if (missingBytesInLastGroup == 1) {

int ch2 = base64toInt(s.charAt(inCursor++), alphaToInt);

result[outCursor++] = (byte) ((ch1 << 4) | (ch2 >> 2));

}

}

// assert inCursor == s.length()-missingBytesInLastGroup;

// assert outCursor == result.length;

return result;

}

/**

* Translates the specified character, which is assumed to be in the “Base 64 Alphabet” into its equivalent 6-bit

* positive integer.

*

* @throw IllegalArgumentException or ArrayOutOfBoundsException if c is not in the Base64 Alphabet.

*/

private static int base64toInt(char c, byte[] alphaToInt) { int result = alphaToInt[c];

if (result < 0) {

throw new IllegalArgumentException(“Illegal character ” + c);

}

return result;

}

/**

* This array is a lookup table that translates unicode characters drawn from the “Base64 Alphabet” (as specified in

* Table 1 of RFC 2045) into their 6-bit positive integer equivalents. Characters that are not in the Base64

* alphabet but fall within the bounds of the array are translated to -1.

*/

private static final byte base64ToInt[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,

-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62,

-1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7,

8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28,

29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 };

/**

* This array is the analogue of base64ToInt, but for the nonstandard variant that avoids the use of uppercase

* alphabetic characters.

*/

private static final byte altBase64ToInt[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,

-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, -1, 62, 9, 10,

11, -1, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 12, 13, 14, -1, 15, 63, 16, -1, -1, -1, -1, -1, -1, -1, -1,

-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 17, -1, 18, 19, 21, 20, 26, 27, 28,

29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 22, 23, 24, 25 };

}


Viewing all articles
Browse latest Browse all 12749

Latest Images

Trending Articles



Latest Images