Application
Spring web application with mysql connection.
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
</dependency>
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
Main
Map an entry for generate encrypted password.
/**
* App.java
*
* REST controller with encrypted DB password
* When using a Map of lists, jdbcTemplate automatically return JSON
*/
package com.minte9.encrypt_password;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
@SpringBootApplication
@RestController
public class App {
@Autowired
private JdbcTemplate jdbcTemplate;
public static void main(String[] args) throws Exception {
SpringApplication.run(App.class, args);
}
@GetMapping("/")
public Object users() {
String sql = "SELECT username FROM users";
List<Map<String, Object>> data = jdbcTemplate.queryForList(sql);
return data;
// [{"username":"aaa"},{"username":"bbb"}]
}
}
Config
Add encrypted password to config.
spring.datasource.url = jdbc:mysql://localhost:3306/db_example
spring.datasource.username = springuser
spring.datasource.password = oKGQSuLmEKbssroQ7XhE2Dy5vKGk2Zd00yXV
spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
# spring.datasource.key = environment_variable
# spring.datasource.iv = environment_variable
Decrypt
DataSource bean in configuration file reads the encrypted password.
/** AppConfig.java
*
* The dataSource() method in the AppConfig class is annotated with @Bean.
* Spring will create a bean of type DataSource using the method
* and will store it in the application context.
*
* When a component in the application needs to connect to the database,
* it simply requests the DataSource from the Spring application context.
*
* Don't keep secrets in play text, use environment variables.
* Use environment variables:
*
* gedit ~/.bashrc
* export SB_ENCRYPT_PASSWORD_KEY=mysecretkey
* export SB_ENCRYPT_PASSWORD_IV=mysecretiv
* source ~/.bashrc
* echo $MYAPP_ENCRYPTION_KEY
*
*/
package com.minte9.encrypt_password;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
@Configuration
public class AppConfig {
@Autowired
private Environment env;
private Boolean ENCRYPT = false;
private Boolean GENKEYS = false;
public void genkeys() throws Exception {
String key = AES_GCM.createKey(256);
String iv = AES_GCM.createIv();
System.out.println(key); // AO5uMsQyKeVfwkVF5L6n0S...
System.out.println(iv); // DnGotRRpb6xlzeu5
System.exit(0);
}
private void encrypt() throws Exception {
String plainText = "The??...";
String key = System.getenv("SB_ENCRYPT_PASSWORD_KEY");
String iv = System.getenv("SB_ENCRYPT_PASSWORD_IV");
String encrypted = AES_GCM.encrypt(plainText, key, iv); // Look Here
System.out.println(encrypted); // FMmsKpM1DizBbpxKuQl5deeA...
System.exit(0);
}
@Bean
public DataSource dataSource () throws Exception {
if (ENCRYPT) encrypt();
if (GENKEYS) genkeys();
String encrypted = env.getProperty("spring.datasource.password");
String key = System.getenv("SB_ENCRYPT_PASSWORD_KEY");
String iv = System.getenv("SB_ENCRYPT_PASSWORD_IV");
String decrypted = AES_GCM.decrypt(encrypted, key, iv); // Look Here
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
// oracle.jdbc.OracleDriver
dataSource.setUrl(env.getProperty("spring.datasource.url"));
dataSource.setUsername(env.getProperty("spring.datasource.username"));
dataSource.setPassword(decrypted);
return dataSource;
}
}
AES GCM
GCM is proven secure in the concrete security model.
/**
* AES GCM cipher
*
* GCM is proven secure in the concrete security model.
* The ECB can leak information about the plaintext.
*/
package com.minte9.encrypt_password;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class AES_GCM {
public static String encrypt(String plainText, String key, String ivStr)
throws Exception {
byte[] iv = Base64.getDecoder().decode(ivStr);
SecretKey secretKey = AES_GCM.getSecretKey(key);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(
Cipher.ENCRYPT_MODE, secretKey, new GCMParameterSpec(128, iv)
);
return Base64.getEncoder().encodeToString(
cipher.doFinal(plainText.getBytes("UTF-8"))
);
}
public static String decrypt(String encryptedText, String key, String ivStr)
throws Exception {
byte[] iv = Base64.getDecoder().decode(ivStr);
SecretKey secretKey = AES_GCM.getSecretKey(key);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(
Cipher.DECRYPT_MODE, secretKey, new GCMParameterSpec(128, iv)
);
return new String(cipher.doFinal(
Base64.getDecoder().decode(encryptedText)
));
}
public static String createKey(int size)
throws NoSuchAlgorithmException {
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256);
SecretKey secretKey = keyGen.generateKey();
return Base64.getEncoder().encodeToString(secretKey.getEncoded());
}
public static String createIv() {
byte[] iv = new byte[12];
new SecureRandom().nextBytes(iv);
return Base64.getEncoder().encodeToString(iv);
}
public static SecretKey getSecretKey(String key) {
byte[] decoded = Base64.getDecoder().decode(key);
return new SecretKeySpec(decoded, 0, decoded.length, "AES");
}
}
Last update: 432 days ago