This repository has been archived by the owner on Dec 17, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 39
/
Encryption.java
125 lines (106 loc) · 4.75 KB
/
Encryption.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package nu.studer.gradle.credentials.domain;
import nu.studer.gradle.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.GeneralSecurityException;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.KeySpec;
/**
* Encryption/decryption of text using ciphers.
* <p>
* Note: The author of this class is by far not a security expert. The chosen implementation has been primarily gathered from examples in the javax.crypto Javadoc and from
* discussions on StackOverflow.
* <p>
* See also <a href="http://stackoverflow.com/questions/992019/java-256-bit-aes-password-based-encryption">here</a> for a more detailed explanation on the selected security
* algorithms.
*/
public final class Encryption {
private static final String UTF_8_CHARSET = "UTF8";
private final Cipher ecipher;
private final Cipher dcipher;
public Encryption(Cipher ecipher, Cipher dcipher) throws GeneralSecurityException {
this.ecipher = ecipher;
this.dcipher = dcipher;
}
/**
* Encrypts the given text.
*
* @param string the text to encrypt
* @return the encrypted text
*/
public String encrypt(String string) {
try {
byte[] utf8 = string.getBytes(UTF_8_CHARSET);
byte[] enc = ecipher.doFinal(utf8);
return Base64.encodeBase64(enc);
} catch (Exception e) {
throw new RuntimeException("Encryption failed: " + e.getMessage(), e);
}
}
/**
* Decrypts the given text.
*
* @param string the text to decrypt
* @return the decrypted text
*/
public String decrypt(String string) {
try {
byte[] dec = Base64.decodeBase64(string);
byte[] utf8 = dcipher.doFinal(dec);
return new String(utf8, UTF_8_CHARSET);
} catch (Exception e) {
throw new RuntimeException("Decryption failed: " + e.getMessage(), e);
}
}
/**
* Creates a new Encryption instance that uses password-based encryption (PBE). The algorithm used to create the secret key is <i>PBEWithMD5AndDES</i>.
*
* @param passphrase the passphrase to apply when creating the secret key
* @return the new Encryption instance
* @throws RuntimeException with wrapped GeneralSecurityException in case of crypto-related exceptions
*/
public static Encryption createEncryption(char[] passphrase) {
try {
return createEncryptionThrowingException(passphrase);
} catch (GeneralSecurityException e) {
throw new RuntimeException("Cannot create Encryption instance: " + e.getMessage(), e);
}
}
private static Encryption createEncryptionThrowingException(char[] passphrase) throws GeneralSecurityException {
// define a salt to prevent dictionary attacks (ideally, the salt would be
// regenerated each time and stored alongside the encrypted text)
byte[] salt = {
(byte) 0x1F, (byte) 0x13, (byte) 0xE5, (byte) 0xB2,
(byte) 0x49, (byte) 0x2C, (byte) 0xC3, (byte) 0x3C
};
// use a high iteration count to slow down the decryption speed
int iterationCount = 65536;
// use the maximum key length that does not require to install the JRE Security Extension
int keyLength = 128;
// provide password, salt, iteration count, and key length for generating the PBEKey
KeySpec pbeKeySpec = new PBEKeySpec(passphrase, salt, iterationCount, keyLength);
// create a secret (symmetric) key using PBE with SHA1 and AES
SecretKeyFactory keyFac = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
SecretKey tmpKey = keyFac.generateSecret(pbeKeySpec);
SecretKey pbeKey = new SecretKeySpec(tmpKey.getEncoded(), "AES");
// create a fixed iv spec that can be used both for encryption and for later decryption
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
int blockSize = cipher.getBlockSize();
byte[] iv = new byte[blockSize];
for (int i = 0; i < iv.length; i++) {
iv[i] = (byte) i;
}
AlgorithmParameterSpec ivSpec = new IvParameterSpec(iv);
// initialize the encryption cipher
Cipher pbeEcipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
pbeEcipher.init(Cipher.ENCRYPT_MODE, pbeKey, ivSpec);
// initialize the decryption cipher
Cipher pbeDcipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
pbeDcipher.init(Cipher.DECRYPT_MODE, pbeKey, ivSpec);
return new Encryption(pbeEcipher, pbeDcipher);
}
}