minte9
LearnRemember



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