Skip to content

Commit c9fa435

Browse files
authored
Fix: Initialization vector cannot be reused (#1858)
1 parent 7c61330 commit c9fa435

File tree

2 files changed

+21
-6
lines changed

2 files changed

+21
-6
lines changed

src/main/java/com/microsoft/sqlserver/jdbc/SecureStringUtil.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,6 @@ final class SecureStringUtil {
3131
/* authentication tag length in bits */
3232
static final int TAG_LENGTH = 16;
3333

34-
/* initialization vector */
35-
byte[] iv;
36-
3734
/** secret key for encryption/decryption */
3835
SecretKeySpec secretKey;
3936

@@ -68,7 +65,6 @@ static SecureStringUtil getInstance() throws SQLServerException {
6865
* if error
6966
*/
7067
private SecureStringUtil() throws SQLServerException {
71-
iv = new byte[IV_LENGTH];
7268
try {
7369
// generate key */
7470
KeyGenerator keygen = KeyGenerator.getInstance(KEYGEN_ALGORITHEM);
@@ -99,6 +95,8 @@ private SecureStringUtil() throws SQLServerException {
9995
byte[] getEncryptedBytes(char[] chars) throws SQLServerException {
10096
if (chars == null)
10197
return null;
98+
99+
byte[] iv = new byte[IV_LENGTH];
102100
SecureRandom random = new SecureRandom();
103101
random.nextBytes(iv);
104102
GCMParameterSpec ivParamSpec = new GCMParameterSpec(TAG_LENGTH * 8, iv);
@@ -107,7 +105,10 @@ byte[] getEncryptedBytes(char[] chars) throws SQLServerException {
107105
encryptCipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParamSpec);
108106

109107
byte[] cipherText = encryptCipher.doFinal(Util.charsToBytes(chars));
110-
return cipherText;
108+
byte[] bytes = new byte[iv.length + cipherText.length];
109+
System.arraycopy(iv, 0, bytes, 0, iv.length);
110+
System.arraycopy(cipherText, 0, bytes, iv.length, cipherText.length);
111+
return bytes;
111112
} catch (Exception e) {
112113
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_EncryptionFailed"));
113114
Object[] msgArgs = {e.getMessage()};
@@ -127,13 +128,17 @@ byte[] getEncryptedBytes(char[] chars) throws SQLServerException {
127128
char[] getDecryptedChars(byte[] bytes) throws SQLServerException {
128129
if (bytes == null)
129130
return null;
131+
132+
byte[] iv = new byte[IV_LENGTH];
133+
System.arraycopy(bytes, 0, iv, 0, IV_LENGTH);
134+
130135
GCMParameterSpec ivParamSpec = new GCMParameterSpec(TAG_LENGTH * 8, iv);
131136

132137
byte[] plainText = null;
133138
try {
134139
decryptCipher.init(Cipher.DECRYPT_MODE, secretKey, ivParamSpec);
135140

136-
plainText = decryptCipher.doFinal(bytes);
141+
plainText = decryptCipher.doFinal(bytes, IV_LENGTH, bytes.length - IV_LENGTH);
137142
return Util.bytesToChars(plainText);
138143
} catch (Exception e) {
139144
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_DecryptionFailed"));

src/test/java/com/microsoft/sqlserver/jdbc/UtilTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ public void testparseUrl() throws SQLException {
6666
}
6767

6868
private static String testString = "A ß € 嗨 𝄞 🙂ăѣ𝔠ծềſģȟᎥ𝒋ǩľḿꞑȯ𝘱𝑞𝗋𝘴ȶ𝞄𝜈ψ𝒙𝘆𝚣1234567890!@#$%^&*()-_=+[{]};:'\",<.>/?~𝘈Ḇ𝖢𝕯٤ḞԍНǏ𝙅ƘԸⲘ𝙉০Ρ𝗤Ɍ𝓢ȚЦ𝒱Ѡ𝓧ƳȤѧᖯć𝗱ễ𝑓𝙜Ⴙ𝞲𝑗𝒌ļṃʼnо𝞎𝒒ᵲꜱ𝙩ừ𝗏ŵ𝒙𝒚ź1234567890!@#$%^&*()-_=+[{]};:'\",<.>/?~АḂⲤ𝗗𝖤𝗙ꞠꓧȊ𝐉𝜥ꓡ𝑀𝑵Ǭ𝙿𝑄Ŗ𝑆𝒯𝖴𝘝𝘞ꓫŸ𝜡ả𝘢ƀ𝖼ḋếᵮℊ𝙝Ꭵ𝕛кιṃդⱺ𝓅𝘲𝕣𝖘ŧ𝑢ṽẉ𝘅ყž1234567890!@#$%^&*()-_=+[{]};:'\",<.>/?~Ѧ𝙱ƇᗞΣℱԍҤ١𝔍К𝓛𝓜ƝȎ𝚸𝑄Ṛ𝓢ṮṺƲᏔꓫ𝚈𝚭𝜶Ꮟçძ𝑒𝖿𝗀ḧ𝗂𝐣ҝɭḿ𝕟𝐨𝝔𝕢ṛ𝓼тú𝔳ẃ⤬𝝲𝗓1234567890!@#$%^&*()-_=+[{]};:'\",<.>/?~𝖠Β𝒞𝘋𝙴𝓕ĢȞỈ𝕵ꓗʟ𝙼ℕ০𝚸𝗤ՀꓢṰǓⅤ𝔚Ⲭ𝑌𝙕𝘢𝕤";
69+
private static String testString2 = "ssdfsdflkjh9u0345)*&)(*&%$";
70+
private static String testString3 = "ss345(*&^%oujdf.';lk2345(*&()*$#~!`1\\]wer><.,/?dfsdflkjh9u0345)*&)(*&%$";
6971

7072
@Test
7173
public void testArrayConversions() {
@@ -79,9 +81,17 @@ public void testArrayConversions() {
7981

8082
@Test
8183
public void testSecureStringUtil() throws SQLException {
84+
// Encrypt/decrypt multiple values in overlapping orders
8285
byte[] bytes = SecureStringUtil.getInstance().getEncryptedBytes(testString.toCharArray());
86+
byte[] bytes2 = SecureStringUtil.getInstance().getEncryptedBytes(testString2.toCharArray());
8387
String end = String.valueOf(SecureStringUtil.getInstance().getDecryptedChars(bytes));
88+
byte[] bytes3 = SecureStringUtil.getInstance().getEncryptedBytes(testString3.toCharArray());
89+
String end3 = String.valueOf(SecureStringUtil.getInstance().getDecryptedChars(bytes3));
90+
String end2 = String.valueOf(SecureStringUtil.getInstance().getDecryptedChars(bytes2));
91+
8492
assertEquals(testString, end);
93+
assertEquals(testString2, end2);
94+
assertEquals(testString3, end3);
8595
}
8696

8797
private void writeAndReadLong(long valueToTest) {

0 commit comments

Comments
 (0)