Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Initialization vector cannot be reused #1858

Merged
merged 2 commits into from
Jul 11, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions src/main/java/com/microsoft/sqlserver/jdbc/SecureStringUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,6 @@ final class SecureStringUtil {
/* authentication tag length in bits */
static final int TAG_LENGTH = 16;

/* initialization vector */
byte[] iv;

/** secret key for encryption/decryption */
SecretKeySpec secretKey;

Expand Down Expand Up @@ -68,7 +65,6 @@ static SecureStringUtil getInstance() throws SQLServerException {
* if error
*/
private SecureStringUtil() throws SQLServerException {
iv = new byte[IV_LENGTH];
try {
// generate key */
KeyGenerator keygen = KeyGenerator.getInstance(KEYGEN_ALGORITHEM);
Expand Down Expand Up @@ -99,6 +95,8 @@ private SecureStringUtil() throws SQLServerException {
byte[] getEncryptedBytes(char[] chars) throws SQLServerException {
if (chars == null)
return null;

byte[] iv = new byte[IV_LENGTH];
SecureRandom random = new SecureRandom();
random.nextBytes(iv);
GCMParameterSpec ivParamSpec = new GCMParameterSpec(TAG_LENGTH * 8, iv);
Expand All @@ -107,7 +105,10 @@ byte[] getEncryptedBytes(char[] chars) throws SQLServerException {
encryptCipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParamSpec);

byte[] cipherText = encryptCipher.doFinal(Util.charsToBytes(chars));
return cipherText;
byte[] bytes = new byte[iv.length + cipherText.length];
System.arraycopy(iv, 0, bytes, 0, iv.length);
System.arraycopy(cipherText, 0, bytes, iv.length, cipherText.length);
return bytes;
} catch (Exception e) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_EncryptionFailed"));
Object[] msgArgs = {e.getMessage()};
Expand All @@ -127,13 +128,19 @@ byte[] getEncryptedBytes(char[] chars) throws SQLServerException {
char[] getDecryptedChars(byte[] bytes) throws SQLServerException {
if (bytes == null)
return null;

byte[] iv = new byte[IV_LENGTH];
byte[] encryptedBytes = new byte[bytes.length - IV_LENGTH];
System.arraycopy(bytes, 0, iv, 0, IV_LENGTH);
System.arraycopy(bytes, IV_LENGTH, encryptedBytes, 0, bytes.length - IV_LENGTH);

GCMParameterSpec ivParamSpec = new GCMParameterSpec(TAG_LENGTH * 8, iv);

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

plainText = decryptCipher.doFinal(bytes);
plainText = decryptCipher.doFinal(encryptedBytes);
David-Engel marked this conversation as resolved.
Show resolved Hide resolved
return Util.bytesToChars(plainText);
} catch (Exception e) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_DecryptionFailed"));
Expand Down
10 changes: 10 additions & 0 deletions src/test/java/com/microsoft/sqlserver/jdbc/UtilTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ public void testparseUrl() throws SQLException {
}

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

@Test
public void testArrayConversions() {
Expand All @@ -79,9 +81,17 @@ public void testArrayConversions() {

@Test
public void testSecureStringUtil() throws SQLException {
// Encrypt/decrypt multiple values in overlapping orders
byte[] bytes = SecureStringUtil.getInstance().getEncryptedBytes(testString.toCharArray());
byte[] bytes2 = SecureStringUtil.getInstance().getEncryptedBytes(testString2.toCharArray());
String end = String.valueOf(SecureStringUtil.getInstance().getDecryptedChars(bytes));
byte[] bytes3 = SecureStringUtil.getInstance().getEncryptedBytes(testString3.toCharArray());
String end3 = String.valueOf(SecureStringUtil.getInstance().getDecryptedChars(bytes3));
String end2 = String.valueOf(SecureStringUtil.getInstance().getDecryptedChars(bytes2));

assertEquals(testString, end);
assertEquals(testString2, end2);
assertEquals(testString3, end3);
}

private void writeAndReadLong(long valueToTest) {
Expand Down