Take into account remote user input in java/non-constant-time-crypto-comparison

This commit is contained in:
Artem Smotrakov
2021-06-19 15:32:01 +02:00
committed by Fosstars
parent 8e6d227dc0
commit a4f3a5a88e
3 changed files with 187 additions and 98 deletions

View File

@@ -1,41 +1,43 @@
edges
| NonConstantTimeCryptoComparison.java:16:28:16:44 | doFinal(...) : byte[] | NonConstantTimeCryptoComparison.java:17:43:17:51 | actualMac |
| NonConstantTimeCryptoComparison.java:23:28:23:44 | doFinal(...) : byte[] | NonConstantTimeCryptoComparison.java:24:84:24:92 | actualMac : byte[] |
| NonConstantTimeCryptoComparison.java:24:84:24:92 | actualMac : byte[] | NonConstantTimeCryptoComparison.java:24:66:24:93 | castToObjectArray(...) |
| NonConstantTimeCryptoComparison.java:31:21:31:29 | actualMac : byte[] | NonConstantTimeCryptoComparison.java:32:43:32:51 | actualMac |
| NonConstantTimeCryptoComparison.java:47:28:47:40 | sign(...) : byte[] | NonConstantTimeCryptoComparison.java:48:40:48:48 | signature |
| NonConstantTimeCryptoComparison.java:56:21:56:29 | signature : byte[] | NonConstantTimeCryptoComparison.java:57:40:57:48 | signature |
| NonConstantTimeCryptoComparison.java:73:22:73:46 | doFinal(...) : byte[] | NonConstantTimeCryptoComparison.java:74:45:74:47 | tag |
| NonConstantTimeCryptoComparison.java:83:24:83:26 | tag : byte[] | NonConstantTimeCryptoComparison.java:84:40:84:42 | tag |
| NonConstantTimeCryptoComparison.java:93:52:93:54 | tag : ByteBuffer | NonConstantTimeCryptoComparison.java:94:40:94:50 | array(...) |
| NonConstantTimeCryptoComparison.java:103:52:103:54 | tag : ByteBuffer | NonConstantTimeCryptoComparison.java:104:49:104:51 | tag |
| NonConstantTimeCryptoComparison.java:19:28:19:44 | doFinal(...) : byte[] | NonConstantTimeCryptoComparison.java:20:43:20:51 | actualMac |
| NonConstantTimeCryptoComparison.java:28:28:28:40 | doFinal(...) : byte[] | NonConstantTimeCryptoComparison.java:29:84:29:92 | actualMac : byte[] |
| NonConstantTimeCryptoComparison.java:29:84:29:92 | actualMac : byte[] | NonConstantTimeCryptoComparison.java:29:66:29:93 | castToObjectArray(...) |
| NonConstantTimeCryptoComparison.java:36:21:36:29 | actualMac : byte[] | NonConstantTimeCryptoComparison.java:38:43:38:51 | actualMac |
| NonConstantTimeCryptoComparison.java:56:28:56:40 | sign(...) : byte[] | NonConstantTimeCryptoComparison.java:57:40:57:48 | signature |
| NonConstantTimeCryptoComparison.java:67:21:67:29 | signature : byte[] | NonConstantTimeCryptoComparison.java:68:40:68:48 | signature |
| NonConstantTimeCryptoComparison.java:85:22:85:46 | doFinal(...) : byte[] | NonConstantTimeCryptoComparison.java:87:45:87:47 | tag |
| NonConstantTimeCryptoComparison.java:97:24:97:26 | tag : byte[] | NonConstantTimeCryptoComparison.java:98:40:98:42 | tag |
| NonConstantTimeCryptoComparison.java:107:52:107:54 | tag : ByteBuffer | NonConstantTimeCryptoComparison.java:109:40:109:42 | tag : ByteBuffer |
| NonConstantTimeCryptoComparison.java:109:40:109:42 | tag : ByteBuffer | NonConstantTimeCryptoComparison.java:109:40:109:50 | array(...) |
| NonConstantTimeCryptoComparison.java:119:52:119:54 | tag : ByteBuffer | NonConstantTimeCryptoComparison.java:120:49:120:51 | tag |
nodes
| NonConstantTimeCryptoComparison.java:16:28:16:44 | doFinal(...) : byte[] | semmle.label | doFinal(...) : byte[] |
| NonConstantTimeCryptoComparison.java:17:43:17:51 | actualMac | semmle.label | actualMac |
| NonConstantTimeCryptoComparison.java:23:28:23:44 | doFinal(...) : byte[] | semmle.label | doFinal(...) : byte[] |
| NonConstantTimeCryptoComparison.java:24:66:24:93 | castToObjectArray(...) | semmle.label | castToObjectArray(...) |
| NonConstantTimeCryptoComparison.java:24:84:24:92 | actualMac : byte[] | semmle.label | actualMac : byte[] |
| NonConstantTimeCryptoComparison.java:31:21:31:29 | actualMac : byte[] | semmle.label | actualMac : byte[] |
| NonConstantTimeCryptoComparison.java:32:43:32:51 | actualMac | semmle.label | actualMac |
| NonConstantTimeCryptoComparison.java:47:28:47:40 | sign(...) : byte[] | semmle.label | sign(...) : byte[] |
| NonConstantTimeCryptoComparison.java:48:40:48:48 | signature | semmle.label | signature |
| NonConstantTimeCryptoComparison.java:56:21:56:29 | signature : byte[] | semmle.label | signature : byte[] |
| NonConstantTimeCryptoComparison.java:19:28:19:44 | doFinal(...) : byte[] | semmle.label | doFinal(...) : byte[] |
| NonConstantTimeCryptoComparison.java:20:43:20:51 | actualMac | semmle.label | actualMac |
| NonConstantTimeCryptoComparison.java:28:28:28:40 | doFinal(...) : byte[] | semmle.label | doFinal(...) : byte[] |
| NonConstantTimeCryptoComparison.java:29:66:29:93 | castToObjectArray(...) | semmle.label | castToObjectArray(...) |
| NonConstantTimeCryptoComparison.java:29:84:29:92 | actualMac : byte[] | semmle.label | actualMac : byte[] |
| NonConstantTimeCryptoComparison.java:36:21:36:29 | actualMac : byte[] | semmle.label | actualMac : byte[] |
| NonConstantTimeCryptoComparison.java:38:43:38:51 | actualMac | semmle.label | actualMac |
| NonConstantTimeCryptoComparison.java:56:28:56:40 | sign(...) : byte[] | semmle.label | sign(...) : byte[] |
| NonConstantTimeCryptoComparison.java:57:40:57:48 | signature | semmle.label | signature |
| NonConstantTimeCryptoComparison.java:73:22:73:46 | doFinal(...) : byte[] | semmle.label | doFinal(...) : byte[] |
| NonConstantTimeCryptoComparison.java:74:45:74:47 | tag | semmle.label | tag |
| NonConstantTimeCryptoComparison.java:83:24:83:26 | tag : byte[] | semmle.label | tag : byte[] |
| NonConstantTimeCryptoComparison.java:84:40:84:42 | tag | semmle.label | tag |
| NonConstantTimeCryptoComparison.java:93:52:93:54 | tag : ByteBuffer | semmle.label | tag : ByteBuffer |
| NonConstantTimeCryptoComparison.java:94:40:94:50 | array(...) | semmle.label | array(...) |
| NonConstantTimeCryptoComparison.java:103:52:103:54 | tag : ByteBuffer | semmle.label | tag : ByteBuffer |
| NonConstantTimeCryptoComparison.java:104:49:104:51 | tag | semmle.label | tag |
| NonConstantTimeCryptoComparison.java:67:21:67:29 | signature : byte[] | semmle.label | signature : byte[] |
| NonConstantTimeCryptoComparison.java:68:40:68:48 | signature | semmle.label | signature |
| NonConstantTimeCryptoComparison.java:85:22:85:46 | doFinal(...) : byte[] | semmle.label | doFinal(...) : byte[] |
| NonConstantTimeCryptoComparison.java:87:45:87:47 | tag | semmle.label | tag |
| NonConstantTimeCryptoComparison.java:97:24:97:26 | tag : byte[] | semmle.label | tag : byte[] |
| NonConstantTimeCryptoComparison.java:98:40:98:42 | tag | semmle.label | tag |
| NonConstantTimeCryptoComparison.java:107:52:107:54 | tag : ByteBuffer | semmle.label | tag : ByteBuffer |
| NonConstantTimeCryptoComparison.java:109:40:109:42 | tag : ByteBuffer | semmle.label | tag : ByteBuffer |
| NonConstantTimeCryptoComparison.java:109:40:109:50 | array(...) | semmle.label | array(...) |
| NonConstantTimeCryptoComparison.java:119:52:119:54 | tag : ByteBuffer | semmle.label | tag : ByteBuffer |
| NonConstantTimeCryptoComparison.java:120:49:120:51 | tag | semmle.label | tag |
#select
| NonConstantTimeCryptoComparison.java:17:43:17:51 | actualMac | NonConstantTimeCryptoComparison.java:16:28:16:44 | doFinal(...) : byte[] | NonConstantTimeCryptoComparison.java:17:43:17:51 | actualMac | Using a non-constant time algorithm for comparing results of a cryptographic operation. |
| NonConstantTimeCryptoComparison.java:24:66:24:93 | castToObjectArray(...) | NonConstantTimeCryptoComparison.java:23:28:23:44 | doFinal(...) : byte[] | NonConstantTimeCryptoComparison.java:24:66:24:93 | castToObjectArray(...) | Using a non-constant time algorithm for comparing results of a cryptographic operation. |
| NonConstantTimeCryptoComparison.java:32:43:32:51 | actualMac | NonConstantTimeCryptoComparison.java:31:21:31:29 | actualMac : byte[] | NonConstantTimeCryptoComparison.java:32:43:32:51 | actualMac | Using a non-constant time algorithm for comparing results of a cryptographic operation. |
| NonConstantTimeCryptoComparison.java:48:40:48:48 | signature | NonConstantTimeCryptoComparison.java:47:28:47:40 | sign(...) : byte[] | NonConstantTimeCryptoComparison.java:48:40:48:48 | signature | Using a non-constant time algorithm for comparing results of a cryptographic operation. |
| NonConstantTimeCryptoComparison.java:57:40:57:48 | signature | NonConstantTimeCryptoComparison.java:56:21:56:29 | signature : byte[] | NonConstantTimeCryptoComparison.java:57:40:57:48 | signature | Using a non-constant time algorithm for comparing results of a cryptographic operation. |
| NonConstantTimeCryptoComparison.java:74:45:74:47 | tag | NonConstantTimeCryptoComparison.java:73:22:73:46 | doFinal(...) : byte[] | NonConstantTimeCryptoComparison.java:74:45:74:47 | tag | Using a non-constant time algorithm for comparing results of a cryptographic operation. |
| NonConstantTimeCryptoComparison.java:84:40:84:42 | tag | NonConstantTimeCryptoComparison.java:83:24:83:26 | tag : byte[] | NonConstantTimeCryptoComparison.java:84:40:84:42 | tag | Using a non-constant time algorithm for comparing results of a cryptographic operation. |
| NonConstantTimeCryptoComparison.java:94:40:94:50 | array(...) | NonConstantTimeCryptoComparison.java:93:52:93:54 | tag : ByteBuffer | NonConstantTimeCryptoComparison.java:94:40:94:50 | array(...) | Using a non-constant time algorithm for comparing results of a cryptographic operation. |
| NonConstantTimeCryptoComparison.java:104:49:104:51 | tag | NonConstantTimeCryptoComparison.java:103:52:103:54 | tag : ByteBuffer | NonConstantTimeCryptoComparison.java:104:49:104:51 | tag | Using a non-constant time algorithm for comparing results of a cryptographic operation. |
| NonConstantTimeCryptoComparison.java:20:43:20:51 | actualMac | NonConstantTimeCryptoComparison.java:19:28:19:44 | doFinal(...) : byte[] | NonConstantTimeCryptoComparison.java:20:43:20:51 | actualMac | Using a non-constant time algorithm for comparing results of a cryptographic operation. |
| NonConstantTimeCryptoComparison.java:29:66:29:93 | castToObjectArray(...) | NonConstantTimeCryptoComparison.java:28:28:28:40 | doFinal(...) : byte[] | NonConstantTimeCryptoComparison.java:29:66:29:93 | castToObjectArray(...) | Using a non-constant time algorithm for comparing results of a cryptographic operation. |
| NonConstantTimeCryptoComparison.java:38:43:38:51 | actualMac | NonConstantTimeCryptoComparison.java:36:21:36:29 | actualMac : byte[] | NonConstantTimeCryptoComparison.java:38:43:38:51 | actualMac | Using a non-constant time algorithm for comparing results of a cryptographic operation. |
| NonConstantTimeCryptoComparison.java:57:40:57:48 | signature | NonConstantTimeCryptoComparison.java:56:28:56:40 | sign(...) : byte[] | NonConstantTimeCryptoComparison.java:57:40:57:48 | signature | Using a non-constant time algorithm for comparing results of a cryptographic operation. |
| NonConstantTimeCryptoComparison.java:68:40:68:48 | signature | NonConstantTimeCryptoComparison.java:67:21:67:29 | signature : byte[] | NonConstantTimeCryptoComparison.java:68:40:68:48 | signature | Using a non-constant time algorithm for comparing results of a cryptographic operation. |
| NonConstantTimeCryptoComparison.java:87:45:87:47 | tag | NonConstantTimeCryptoComparison.java:85:22:85:46 | doFinal(...) : byte[] | NonConstantTimeCryptoComparison.java:87:45:87:47 | tag | Using a non-constant time algorithm for comparing results of a cryptographic operation. |
| NonConstantTimeCryptoComparison.java:98:40:98:42 | tag | NonConstantTimeCryptoComparison.java:97:24:97:26 | tag : byte[] | NonConstantTimeCryptoComparison.java:98:40:98:42 | tag | Using a non-constant time algorithm for comparing results of a cryptographic operation. |
| NonConstantTimeCryptoComparison.java:109:40:109:50 | array(...) | NonConstantTimeCryptoComparison.java:107:52:107:54 | tag : ByteBuffer | NonConstantTimeCryptoComparison.java:109:40:109:50 | array(...) | Using a non-constant time algorithm for comparing results of a cryptographic operation. |
| NonConstantTimeCryptoComparison.java:120:49:120:51 | tag | NonConstantTimeCryptoComparison.java:119:52:119:54 | tag : ByteBuffer | NonConstantTimeCryptoComparison.java:120:49:120:51 | tag | Using a non-constant time algorithm for comparing results of a cryptographic operation. |

View File

@@ -1,3 +1,4 @@
import java.net.Socket;
import java.nio.ByteBuffer;
import java.security.Key;
import java.security.MessageDigest;
@@ -11,73 +12,86 @@ import javax.crypto.Mac;
public class NonConstantTimeCryptoComparison {
// BAD: compare MACs using a non-constant time method
public boolean unsafeMacCheckWithArrayEquals(byte[] expectedMac, byte[] data) throws Exception {
public boolean unsafeMacCheckWithArrayEquals(byte[] expectedMac, Socket socket) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
byte[] data = new byte[1024];
socket.getInputStream().read(data);
byte[] actualMac = mac.doFinal(data);
return Arrays.equals(expectedMac, actualMac);
}
// BAD: compare MACs using a non-constant time method
public boolean unsafeMacCheckWithArraysDeepEquals(byte[] expectedMac, byte[] data) throws Exception {
public boolean unsafeMacCheckWithArraysDeepEquals(byte[] expectedMac, Socket socket) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
byte[] actualMac = mac.doFinal(data);
byte[] data = socket.getInputStream().readAllBytes();
mac.update(data);
byte[] actualMac = mac.doFinal();
return Arrays.deepEquals(castToObjectArray(expectedMac), castToObjectArray(actualMac));
}
// BAD: compare MACs using a non-constant time method
public boolean unsafeMacCheckWithDoFinalWithOutputArray(byte[] expectedMac, byte[] data) throws Exception {
public boolean unsafeMacCheckWithDoFinalWithOutputArray(byte[] data, Socket socket) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
byte[] actualMac = new byte[256];
mac.doFinal(actualMac, 0);
byte[] expectedMac = socket.getInputStream().readNBytes(256);
return Arrays.equals(expectedMac, actualMac);
}
// GOOD: compare MACs using a constant time method
public boolean saferMacCheck(byte[] expectedMac, byte[] data) throws Exception {
public boolean saferMacCheck(byte[] expectedMac, Socket socket) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
byte[] data = new byte[1024];
socket.getInputStream().read(data);
byte[] actualMac = mac.doFinal(data);
return MessageDigest.isEqual(expectedMac, actualMac);
}
// BAD: compare signatures using a non-constant time method
public boolean unsafeCheckSignatures(byte[] expected, byte[] data, PrivateKey key) throws Exception {
public boolean unsafeCheckSignatures(byte[] expected, Socket socket, PrivateKey key) throws Exception {
Signature engine = Signature.getInstance("SHA256withRSA");
engine.initSign(key);
byte[] data = socket.getInputStream().readAllBytes();
engine.update(data);
byte[] signature = engine.sign();
return Arrays.equals(expected, signature);
}
// BAD: compare signatures using a non-constant time method
public boolean unsafeCheckSignaturesWithOutputArray(byte[] expected, byte[] data, PrivateKey key) throws Exception {
public boolean unsafeCheckSignaturesWithOutputArray(byte[] expected, Socket socket, PrivateKey key) throws Exception {
Signature engine = Signature.getInstance("SHA256withRSA");
engine.initSign(key);
byte[] data = socket.getInputStream().readAllBytes();
engine.update(data);
byte[] signature = new byte[1024];
engine.sign(signature, 0, 1024);
return Arrays.equals(expected, signature);
}
// GOOD: compare signatures using a constant time method
public boolean saferCheckSignatures(byte[] expected, byte[] data, PrivateKey key) throws Exception {
public boolean saferCheckSignatures(byte[] expected, Socket socket, PrivateKey key) throws Exception {
Signature engine = Signature.getInstance("SHA256withRSA");
engine.initSign(key);
byte[] data = socket.getInputStream().readAllBytes();
engine.update(data);
byte[] signature = engine.sign();
return MessageDigest.isEqual(expected, signature);
}
// BAD: compare ciphertexts using a non-constant time method
public boolean unsafeCheckCiphertext(byte[] expected, byte[] plaintext, Key key) throws Exception {
public boolean unsafeCheckCiphertext(Socket socket, byte[] plaintext, Key key) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] tag = cipher.doFinal(plaintext);
byte[] expected = socket.getInputStream().readAllBytes();
return Objects.deepEquals(expected, tag);
}
// BAD: compare ciphertexts using a non-constant time method
public boolean unsafeCheckCiphertextWithOutputArray(byte[] expected, byte[] plaintext, Key key) throws Exception {
public boolean unsafeCheckCiphertextWithOutputArray(byte[] expected, Socket socket, Key key) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] plaintext = socket.getInputStream().readAllBytes();
cipher.update(plaintext);
byte[] tag = new byte[1024];
cipher.doFinal(tag, 0);
@@ -85,19 +99,21 @@ public class NonConstantTimeCryptoComparison {
}
// BAD: compare ciphertexts using a non-constant time method
public boolean unsafeCheckCiphertextWithByteBuffer(byte[] expected, byte[] plaintext, Key key) throws Exception {
public boolean unsafeCheckCiphertextWithByteBuffer(Socket socket, byte[] plaintext, Key key) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
cipher.update(plaintext);
ByteBuffer tag = ByteBuffer.wrap(new byte[1024]);
cipher.doFinal(ByteBuffer.wrap(plaintext), tag);
byte[] expected = socket.getInputStream().readNBytes(1024);
return Arrays.equals(expected, tag.array());
}
// BAD: compare ciphertexts using a non-constant time method
public boolean unsafeCheckCiphertextWithByteBufferEquals(byte[] expected, byte[] plaintext, Key key) throws Exception {
public boolean unsafeCheckCiphertextWithByteBufferEquals(byte[] expected, Socket socket, Key key) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] plaintext = socket.getInputStream().readAllBytes();
cipher.update(plaintext);
ByteBuffer tag = ByteBuffer.wrap(new byte[1024]);
cipher.doFinal(ByteBuffer.wrap(plaintext), tag);
@@ -105,10 +121,11 @@ public class NonConstantTimeCryptoComparison {
}
// GOOD: compare ciphertexts using a constant time method
public boolean saferCheckCiphertext(byte[] expected, byte[] plaintext, Key key) throws Exception {
public boolean saferCheckCiphertext(Socket socket, byte[] plaintext, Key key) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] tag = cipher.doFinal(plaintext);
byte[] expected = socket.getInputStream().readAllBytes();
return MessageDigest.isEqual(expected, tag);
}