forked from jpos/jPOS-EE
/
SensitiveString.java
101 lines (89 loc) · 4 KB
/
SensitiveString.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
/*
* jPOS Project [http://jpos.org]
* Copyright (C) 2000-2020 jPOS Software SRL
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.jpos.crypto;
import org.jpos.iso.ISOUtil;
import org.jpos.security.SystemSeed;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import java.nio.ByteBuffer;
import java.security.*;
import java.util.Arrays;
import java.util.Objects;
import java.util.Random;
import java.util.function.Supplier;
public class SensitiveString implements Supplier<String> {
private SecretKey key;
private byte[] encoded;
private static Random rnd;
private static final String AES = "AES/CBC/PKCS5Padding";
static {
rnd = new SecureRandom();
}
public SensitiveString(String s) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, NoSuchProviderException, InvalidAlgorithmParameterException {
key = generateKey();
encoded = encrypt(s.getBytes());
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SensitiveString that = (SensitiveString) o;
return this.get().equals(that.get());
}
private SecretKey generateKey() throws NoSuchAlgorithmException {
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
int maxKeyLength = Cipher.getMaxAllowedKeyLength(keyGen.getAlgorithm());
keyGen.init(maxKeyLength == Integer.MAX_VALUE ? 256 : maxKeyLength);
return keyGen.generateKey();
}
private byte[] encrypt(byte[] b) throws NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
final Cipher cipher = Cipher.getInstance(AES);
final byte[] iv = randomIV();
cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
byte[] enc = cipher.doFinal(b);
ByteBuffer buf = ByteBuffer.allocate(iv.length + enc.length);
buf.put(ISOUtil.xor(iv, SystemSeed.getSeed(iv.length, iv.length)));
buf.put(enc);
return buf.array();
}
private byte[] decrypt(byte[] encoded)
throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException,
IllegalBlockSizeException, NoSuchProviderException, InvalidAlgorithmParameterException
{
byte[] iv = new byte[16];
byte[] cryptogram = new byte[encoded.length - iv.length];
System.arraycopy(encoded, 0, iv, 0, iv.length);
System.arraycopy(encoded, iv.length, cryptogram, 0, cryptogram.length);
final Cipher cipher = Cipher.getInstance(AES);
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(ISOUtil.xor(iv, SystemSeed.getSeed(iv.length, iv.length))));
return cipher.doFinal(cryptogram);
}
private byte[] randomIV() {
final byte[] b = new byte[16];
rnd.nextBytes(b);
return b;
}
@Override
public String get() {
try {
return new String(decrypt(encoded));
} catch (NoSuchPaddingException | NoSuchAlgorithmException | BadPaddingException | InvalidKeyException | NoSuchProviderException | IllegalBlockSizeException | InvalidAlgorithmParameterException e) {
throw new AssertionError(e.getMessage());
}
}
}