记录精彩的程序人生

使用 druid-1.0.16.jar 进行数据库密码加密

在我们项目中,经常需要写数据库的配置,这其中就包含数据库的 host 和密码等信息,尤其是密码这一块,经常会给我们造成困扰,比如要提交 GitHub 啊、或者跟其他人进行合作开发之类的,就会造成密码泄漏,继而造成不必要的损失。

但是如果我们是使用的druid 链接池,我们是可以对配置文件里面密码进行加密的,经过加密后,我们就不再需要将明文的密码写在配置文件里面了。

工具

  • 本文用到到 jar 版本是 1.0.16

druid-1.0.16.jar

下载地址

使用方法

  • 首先将该 jar 文件 下载到本地,然后执行一下命令

java -cp druid-1.0.16.jar com.alibaba.druid.filter.config.ConfigTools yourpassword

例如我到密码是 root ,那么需要执行到命令是:

java -cp druid-1.0.16.jar com.alibaba.druid.filter.config.ConfigTools root

执行命令后,会生成相应到 key 值:

aee198e5429649bcb8436323169975a4-image.png

其中包含三个东西:

privateKey: 私密,用来解密用,可以忽略

publickey:公密,用来配置在项目数据源

password:密码,用来配置在数据源处,就是原来明文密码到替代品

  • 修改配置文件

接下来就应该修改配置文件,将原来到明文密码改为加密后到密码

c82eac112b9a49e499318208a012a9dd-image.png

配置文件需要两个地方到修改:

password:配置 利用工具生成到密码

connection-properties : 配置 publickey ,配置格式:connection-properties: config.decrypt=true;config.decrypt.key=后面直接跟生成的 publickey

全部的配置文件如下:

server:
 port: 8088
spring: 
  datasource: 
driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://100.00.000.00:3306/test  # 此处ip 改为你数据库到host
    username: root
    password: your password
    druid:
 filter.config.enabled: true
           connection-properties: config.decrypt=true;config.decrypt.key=yourpublickey
           initial-size: 1
           min-idle: 1
           max-active: 20
           max-wait: 60000
           time-between-eviction-runs-millis: 60000
           min-evictable-idle-time-millis: 300000
           validation-query: select 'x'
           test-while-idle: true
           test-on-borrow: false
           test-on-return: false
           pool-prepared-statements: false
           max-open-prepared-statements: 20
#           stat-view-servlet:
#             enabled: true
#             url-pattern: /druid/*
#             reset-enable: false
#             login-username: admin
#             login-password: 123456
  jpa:
 show-sql: true
    hibernate:
 ddl-auto: create
  thymeleaf:
 encoding: UTF-8
    cache: false

测试

直接启动项目测试即可

---------------------------- 手动分割线 -------------------------------

12 月 23 日更新

昨天忘记说了,可以不用执行那个命令,直接执行源码也是可以的。

源码类路径:

com.alibaba.druid.filter.config.ConfigTools

源码内容如下:在 main 方法里面把 password 改成你自己的就可以了


/*
 * Copyright 1999-2017 Alibaba Group Holding Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.alibaba.druid.filter.config;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
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.NoSuchProviderException;
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;

import com.alibaba.druid.util.Base64;
import com.alibaba.druid.util.JdbcUtils;

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 {
        String password = args[0];
  String[] arr = genKeyPair(512);
  System.out.println("privateKey:" + arr[0]);
  System.out.println("publicKey:" + arr[1]);
  System.out.println("password:" + encrypt(arr[0], password));
  }

   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 {
         JdbcUtils.close(in);
  }
   }

   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", "SunRsaSign");
 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", "SunRsaSign");
 return factory.generatePublic(spec);
  } catch (Exception e) {
         throw new IllegalArgumentException("Failed to get public key", e);
  } finally {
         JdbcUtils.close(in);
  }
   }

   public static String decrypt(PublicKey publicKey, String cipherText)
         throws Exception {
      Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
 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", "SunRsaSign");
  PrivateKey privateKey = factory.generatePrivate(spec);
  Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
 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, NoSuchProviderException {
      byte[][] keyPairBytes = new byte[2][];

  KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA", "SunRsaSign");
  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, NoSuchProviderException {
      byte[][] keyPairBytes = genKeyPairBytes(keySize);
  String[] keyPairs = new String[2];

  keyPairs[0] = Base64.byteArrayToBase64(keyPairBytes[0]);
  keyPairs[1] = Base64.byteArrayToBase64(keyPairBytes[1]);

 return keyPairs;
  }

}


一个可菜可菜的码农

留下你的脚步