At work, I sometimes considered how to deal with cases that presuppose data encryption / decryption, so I will write that I tried it as a reminder.
English but spring.io documentation is helpful spring.io --Encryptors documentation
In Japanese, the TERA SOLUNA document is easy to read 6. Security measures by TERASOLUNA Server Framework for Java (5.x) >> 6.9. Encryption
From the conclusion, it looks like the following (only my personal opinion)
Method | Contents | Cipher mode of operation | Encryption strength |
---|---|---|---|
noOpText | Do not encrypt. It is used as a Mock for implementation. | None | out of the question |
queryableText | Use "standard" password-based encryption. Generate an invariant value. | CBC | Low |
text | Use "standard" password-based encryption. Generate a variable value. | CBC | During ~ |
delux | Use "stronger" password-based encryption. Generate a variable value. | GCM | High |
Create the following sample and try it out.
public class EncryptorTest {
private static String secret = "1234";
private static String salt = "5678";
public static void main(String[] args) throws IOException {
String text = "Hello";
TextEncryptor encryptor1 = Encryptors.noOpText();
String noOpTextEncryptText = encryptor1.encrypt(text);
String noOpTextDecryptText = encryptor1.decrypt(noOpTextEncryptText);
TextEncryptor encryptor2 = Encryptors.queryableText(secret, salt);
String queryableTextEncryptText = encryptor2.encrypt(text);
String queryableTextDecryptText = encryptor2.decrypt(queryableTextEncryptText);
TextEncryptor encryptor3 = Encryptors.text(secret, salt);
String textEncryptText = encryptor3.encrypt(text);
String textDecryptText = encryptor3.decrypt(textEncryptText);
TextEncryptor encryptor4 = Encryptors.delux(secret, salt);
String deluxEncryptText = encryptor4.encrypt(text);
String deluxDecryptText = encryptor4.decrypt(deluxEncryptText);
System.out.println("noOpText() :");
System.out.println ("encryption string:" + noOpTextEncryptText);
System.out.println ("Decryption Confirmation:" + noOpTextDecryptText);
System.out.println("");
System.out.println("queryableText() : ");
System.out.println ("encryption string:" + queryableTextEncryptText);
System.out.println ("Decryption Confirmation:" + queryableTextDecryptText);
System.out.println("");
System.out.println("text() : ");
System.out.println ("encryption string:" + textEncryptText);
System.out.println ("Decryption Confirmation:" + textDecryptText);
System.out.println("");
System.out.println("delux() : ");
System.out.println ("encryption string:" + deluxEncryptText);
System.out.println ("Decryption Confirmation:" + deluxDecryptText);
}
noOpText() :
Encrypted string: Hello
Decryption confirmation: Hello
queryableText() :
Encrypted string: 524110739525b3f266a0064b4229a77d
Decryption confirmation: Hello
text() :
Encrypted string: ced1eb40b88e691f502d548ed17752bff82592da917804ea66ea1a49bfa77033
Decryption confirmation: Hello
delux() :
Encrypted string: 61e62f473d0cb228305081b927a3225d487a749b87af62071ad60dc6b27703410de45f7fbf
Decryption confirmation: Hello
Although the character length of the encryption is different, it can be seen that the decryption from the encryption is possible in each case. Let's take a look at the logic of each method here to see what the difference is.
noOpText If you create an instance with Encryptors.noOpText () The following logic is called.
private static final class NoOpTextEncryptor implements TextEncryptor {
public String encrypt(String text) {
return text;
}
public String decrypt(String encryptedText) {
return encryptedText;
}
}
I commented that it was out of the question, but I didn't do anything. Is there any use for it ...
queryableText
Then ** queryableText **
public static TextEncryptor queryableText(CharSequence password, CharSequence salt) {
return new HexEncodingTextEncryptor(new AesBytesEncryptor(password.toString(),
salt));
}
public AesBytesEncryptor(String password, CharSequence salt) {
this (password, salt, null); // ← The argument here is null
}
public AesBytesEncryptor(String password, CharSequence salt,
BytesKeyGenerator ivGenerator) {
this(password, salt, ivGenerator, CipherAlgorithm.CBC);
}
public AesBytesEncryptor(String password, CharSequence salt,
BytesKeyGenerator ivGenerator, CipherAlgorithm alg) {
PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray(), Hex.decode(salt),
1024, 256);
SecretKey secretKey = newSecretKey("PBKDF2WithHmacSHA1", keySpec);
this.secretKey = new SecretKeySpec(secretKey.getEncoded(), "AES");
this.alg = alg;
this.encryptor = alg.createCipher();
this.decryptor = alg.createCipher();
this.ivGenerator = ivGenerator != null ? ivGenerator : alg.defaultIvGenerator();
}
text
Leave the comment of ** queryableText ** and leave ** text **
public static TextEncryptor text(CharSequence password, CharSequence salt) {
return new HexEncodingTextEncryptor(standard(password, salt));
}
public static BytesEncryptor standard(CharSequence password, CharSequence salt) {
return new AesBytesEncryptor(password.toString(), salt,
KeyGenerators.secureRandom (16)); // ← The argument here is a random number
}
public AesBytesEncryptor(String password, CharSequence salt,
BytesKeyGenerator ivGenerator) {
this(password, salt, ivGenerator, CipherAlgorithm.CBC);
}
public AesBytesEncryptor(String password, CharSequence salt,
BytesKeyGenerator ivGenerator, CipherAlgorithm alg) {
PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray(), Hex.decode(salt),
1024, 256);
SecretKey secretKey = newSecretKey("PBKDF2WithHmacSHA1", keySpec);
this.secretKey = new SecretKeySpec(secretKey.getEncoded(), "AES");
this.alg = alg;
this.encryptor = alg.createCipher();
this.decryptor = alg.createCipher();
this.ivGenerator = ivGenerator != null ? ivGenerator : alg.defaultIvGenerator();
}
What is the difference between ** queryableText ** and ** text ** The difference is whether to pass BytesKeyGenerator as ** null ** or ** KeyGenerators.secureRandom (16) **.
Since ** queryableText ** is passed as ** null **, it generates the same encrypted string every time. Since ** text ** passes ** KeyGenerators.secureRandom (16) **, a different random number is generated each time, and as a result, a different encrypted string is generated each time.
delux
And finally ** delux **
public static TextEncryptor delux(CharSequence password, CharSequence salt) {
return new HexEncodingTextEncryptor(stronger(password, salt));
}
public static BytesEncryptor stronger(CharSequence password, CharSequence salt) {
return new AesBytesEncryptor(password.toString(), salt,
KeyGenerators.secureRandom(16), CipherAlgorithm.GCM);
}
public AesBytesEncryptor(String password, CharSequence salt,
BytesKeyGenerator ivGenerator, CipherAlgorithm alg) {
PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray(), Hex.decode(salt),
1024, 256);
SecretKey secretKey = newSecretKey("PBKDF2WithHmacSHA1", keySpec);
this.secretKey = new SecretKeySpec(secretKey.getEncoded(), "AES");
this.alg = alg;
this.encryptor = alg.createCipher();
this.decryptor = alg.createCipher();
this.ivGenerator = ivGenerator != null ? ivGenerator : alg.defaultIvGenerator();
}
What is the difference between ** text ** and ** delux **? The difference is whether ** CBC ** or ** GCM ** is specified for CipherAlgorithm.
It is generally said that GCM (Galois / Counter Mode) is capable of parallel processing and is more efficient than CBC. Despite implementing higher encryption than CBC, there is not much difference in processing time.
As a matter of fact, write a process that repeats encryption → decryption 10,000 times and sample it several times. I compared ** text ** and ** delux **, but the processing time was almost the same. (Error less than 1 second)
I felt that it would be better to use ** delux ** unless there was a specific reason. (There are few systems that say that the data length is long in this era, so the disk capacity is ...)
Recommended Posts