Crypto Tool
Spring Boot CommandLineRunner crypto tool.
This tool:
- Runs only when explicitly invoked
- Uses Spring Boot only for lifecycle & DI
- Exists immediately after doing its job
- Does not start Tomcat
- Never runs in production by accident
1. Project structure
You usually put this in a separate module.
crypto-tool/
src/main/java/com/minte9/crypto
├─ CryptoCliApp.java
├─ CryptoCommandRunner.java
└─ AES_GCM.java
pom.xml
2. Pom
Make sure you do NOT include web starters.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
3. Entry point (CLI-only)
package com.example.crypto;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class CryptoCliApp {
public static void main(String[] args) {
SpringApplication
.run(CryptoCliApp.class, args)
.close();
}
}
4. CommandLineRunner
package com.example.crypto.controller;
import com.example.crypto.service.AES_GCM;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class CryptoCommandRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
if (args.length == 0) {
printUsageAndExit();
}
switch (args[0]) {
case "genkeys":
genkeys();
break;
case "encrypt":
if (args.length != 2) {
System.err.println("ERROR: Missing plaintext password");
printUsageAndExit();
}
encrypt(args[1]);
break;
default:
System.err.println("ERRROR: Unknown command: " + args[0]);
printUsageAndExit();
}
}
private void printUsageAndExit() {
System.out.println();
System.out.println("Usage:");
System.out.println(" java -jar crypto-tool.jar genkeys");
System.out.println(" java -jar crypto-tool.jar encrypt \"PlainTextPassword\"");
System.exit(1);
}
private void genkeys() throws Exception {
String key = AES_GCM.createKey(256);
String iv = AES_GCM.createIv();
System.out.println("SB_ENCRYPT_PASSWORD_KEY=" + key);
System.out.println("SB_ENCRYPT_PASSWORD_IV=" + iv);
}
private void encrypt(String platinText) throws Exception {
String key = System.getenv("SB_ENCRYPT_PASSWORD_KEY");
String iv = System.getenv("SB_ENCRYPT_PASSWORD_IV");
if (key == null || iv == null) {
throw new IllegalStateException(
"Missing environment variables: " +
"SB_ENCRYPT_PASSWORD_KEY / SB_ENCRYPT_PASSWORD_IV"
);
}
String encrypted = AES_GCM.encrypt(platinText, key, iv);
System.out.println(encrypted);
}
}
5. AES_GCM cipher
package com.example.crypto.service;
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");
}
}
6. Test it
Generate keys.
mvn package
java -jar .\target\crypto-tool-0.0.1.jar genkeys
Set environment variables (linux):
export SB_ENCRYPT_PASSWORD_KEY="kQvk8AYEaawD1z05AxkM045I8Fi/fVcldA6osPbf6xo="
export SB_ENCRYPT_PASSWORD_IV="Dllfq8jY2t0QmVLN"
Encrypt plain password.
java -jar .\target\crypto-tool-0.0.1.jar encrypt mypass
PowerShell treats $something as a variable expansion, even inside double quotes.
Solution: use single quotes.
java -jar .\target\crypto-tool-0.0.1.jar encrypt 'tgW3$#2222222$11111111'