Merge pull request #12080 from alexrford/js-use-shared-cryptography

JS: Use shared `CryptographicOperation` concept
This commit is contained in:
Alex Ford
2023-02-27 12:26:38 +00:00
committed by GitHub
16 changed files with 368 additions and 151 deletions

View File

@@ -409,7 +409,7 @@ private class CryptographicOperationFlowCharacteristic extends NotASinkCharacter
CryptographicOperationFlowCharacteristic() { this = "CryptographicOperationFlow" }
override predicate appliesToEndpoint(DataFlow::Node n) {
any(CryptographicOperation op).getInput() = n
any(CryptographicOperation op).getAnInput() = n
}
}

View File

@@ -0,0 +1,7 @@
---
category: breaking
---
* The `CryptographicOperation` concept has been changed to use a range pattern. This is a breaking change and existing implementations of `CryptographicOperation` will need to be updated in order to compile. These implementations can be updated by:
1. Extending `CryptographicOperation::Range` rather than `CryptographicOperation`
2. Renaming the `getInput()` member predicate as `getAnInput()`
3. Implementing the `BlockMode getBlockMode()` member predicate. The implementation for this can be `none()` if the operation is a hashing operation or an encryption operation using a stream cipher.

View File

@@ -110,3 +110,40 @@ abstract class PersistentWriteAccess extends DataFlow::Node {
*/
abstract DataFlow::Node getValue();
}
/**
* Provides models for cryptographic things.
*/
module Cryptography {
private import semmle.javascript.internal.ConceptsShared::Cryptography as SC
/**
* A data-flow node that is an application of a cryptographic algorithm. For example,
* encryption, decryption, signature-validation.
*
* Extend this class to refine existing API models. If you want to model new APIs,
* extend `CryptographicOperation::Range` instead.
*/
class CryptographicOperation extends SC::CryptographicOperation instanceof CryptographicOperation::Range {
/**
* DEPRECATED. This predicate has been renamed to `getAnInput`.
*
* To implement `CryptographicOperation`, please extend
* `CryptographicOperation::Range` and implement `getAnInput` instead of
* extending this class directly.
*/
deprecated final DataFlow::Node getInput() { result = this.getAnInput() }
}
class EncryptionAlgorithm = SC::EncryptionAlgorithm;
class HashingAlgorithm = SC::HashingAlgorithm;
class PasswordHashingAlgorithm = SC::PasswordHashingAlgorithm;
module CryptographicOperation = SC::CryptographicOperation;
class BlockMode = SC::BlockMode;
class CryptographicAlgorithm = SC::CryptographicAlgorithm;
}

View File

@@ -3,22 +3,7 @@
*/
import javascript
import semmle.javascript.security.CryptoAlgorithms
/**
* An application of a cryptographic algorithm.
*/
abstract class CryptographicOperation extends DataFlow::Node {
/**
* Gets the input the algorithm is used on, e.g. the plain text input to be encrypted.
*/
abstract DataFlow::Node getInput();
/**
* Gets the applied algorithm.
*/
abstract CryptographicAlgorithm getAlgorithm();
}
import semmle.javascript.Concepts::Cryptography
/**
* A key used in a cryptographic algorithm.
@@ -52,13 +37,21 @@ class CryptographicKeyCredentialsExpr extends CredentialsNode instanceof Cryptog
override string getCredentialsKind() { result = "key" }
}
// Holds if `algorithm` is an `EncryptionAlgorithm` that uses a block cipher
private predicate isBlockEncryptionAlgorithm(CryptographicAlgorithm algorithm) {
algorithm instanceof EncryptionAlgorithm and
not algorithm.(EncryptionAlgorithm).isStreamCipher()
}
/**
* A model of the asmCrypto library.
*/
private module AsmCrypto {
private class Apply extends CryptographicOperation instanceof DataFlow::CallNode {
private class Apply extends CryptographicOperation::Range instanceof DataFlow::CallNode {
DataFlow::Node input;
CryptographicAlgorithm algorithm; // non-functional
private string algorithmName;
private string methodName;
Apply() {
/*
@@ -71,17 +64,31 @@ private module AsmCrypto {
* ```
*/
exists(DataFlow::SourceNode asmCrypto, string algorithmName |
exists(DataFlow::SourceNode asmCrypto |
asmCrypto = DataFlow::globalVarRef("asmCrypto") and
algorithm.matchesName(algorithmName) and
this = asmCrypto.getAPropertyRead(algorithmName).getAMemberCall(_) and
input = this.getAnArgument()
this = asmCrypto.getAPropertyRead(algorithmName).getAMemberCall(methodName) and
input = this.getArgument(0)
)
}
override DataFlow::Node getInput() { result = input }
override DataFlow::Node getAnInput() { result = input }
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
override BlockMode getBlockMode() {
isBlockEncryptionAlgorithm(this.getAlgorithm()) and
result.matchesString(algorithmName)
}
DataFlow::Node getKey() {
methodName = ["encrypt", "decrypt"] and
result = super.getArgument(1)
}
}
private class Key extends CryptographicKey {
Key() { this = any(Apply apply).getKey() }
}
}
@@ -93,7 +100,7 @@ private module BrowserIdCrypto {
Key() { this = any(Apply apply).getKey() }
}
private class Apply extends CryptographicOperation instanceof DataFlow::MethodCallNode {
private class Apply extends CryptographicOperation::Range instanceof DataFlow::MethodCallNode {
CryptographicAlgorithm algorithm; // non-functional
Apply() {
@@ -126,10 +133,13 @@ private module BrowserIdCrypto {
)
}
override DataFlow::Node getInput() { result = super.getArgument(0) }
override DataFlow::Node getAnInput() { result = super.getArgument(0) }
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
// not relevant for browserid-crypto
override BlockMode getBlockMode() { none() }
DataFlow::Node getKey() { result = super.getArgument(1) }
}
}
@@ -139,7 +149,7 @@ private module BrowserIdCrypto {
*/
private module NodeJSCrypto {
private class InstantiatedAlgorithm extends DataFlow::CallNode {
CryptographicAlgorithm algorithm; // non-functional
private string algorithmName;
InstantiatedAlgorithm() {
/*
@@ -158,11 +168,24 @@ private module NodeJSCrypto {
exists(DataFlow::SourceNode mod |
mod = DataFlow::moduleImport("crypto") and
this = mod.getAMemberCall("create" + ["Hash", "Hmac", "Sign", "Cipher"]) and
algorithm.matchesName(this.getArgument(0).getStringValue())
algorithmName = this.getArgument(0).getStringValue()
)
}
CryptographicAlgorithm getAlgorithm() { result = algorithm }
CryptographicAlgorithm getAlgorithm() { result.matchesName(algorithmName) }
private BlockMode getExplicitBlockMode() { result.matchesString(algorithmName) }
BlockMode getBlockMode() {
isBlockEncryptionAlgorithm(this.getAlgorithm()) and
(
if exists(this.getExplicitBlockMode())
then result = this.getExplicitBlockMode()
else
// CBC is the default if not explicitly specified
result = "CBC"
)
}
}
private class CreateKey extends CryptographicKeyCreation, DataFlow::CallNode {
@@ -211,14 +234,16 @@ private module NodeJSCrypto {
override predicate isSymmetricKey() { none() }
}
private class Apply extends CryptographicOperation instanceof DataFlow::MethodCallNode {
private class Apply extends CryptographicOperation::Range instanceof DataFlow::MethodCallNode {
InstantiatedAlgorithm instantiation;
Apply() { this = instantiation.getAMethodCall(any(string m | m = "update" or m = "write")) }
override DataFlow::Node getInput() { result = super.getArgument(0) }
override DataFlow::Node getAnInput() { result = super.getArgument(0) }
override CryptographicAlgorithm getAlgorithm() { result = instantiation.getAlgorithm() }
override BlockMode getBlockMode() { result = instantiation.getBlockMode() }
}
private class Key extends CryptographicKey {
@@ -252,23 +277,18 @@ private module CryptoJS {
/**
* Matches `CryptoJS.<algorithmName>` and `require("crypto-js/<algorithmName>")`
*/
private DataFlow::SourceNode getAlgorithmNode(CryptographicAlgorithm algorithm) {
private API::Node getAlgorithmNode(CryptographicAlgorithm algorithm) {
exists(string algorithmName | algorithm.matchesName(algorithmName) |
exists(DataFlow::SourceNode mod | mod = DataFlow::moduleImport("crypto-js") |
result = mod.getAPropertyRead(algorithmName) or
result = mod.getAPropertyRead("Hmac" + algorithmName) // they prefix Hmac
exists(API::Node mod | mod = API::moduleImport("crypto-js") |
result = mod.getMember(algorithmName) or
result = mod.getMember("Hmac" + algorithmName) // they prefix Hmac
)
or
exists(DataFlow::SourceNode mod |
mod = DataFlow::moduleImport("crypto-js/" + algorithmName) and
result = mod
)
result = API::moduleImport("crypto-js/" + algorithmName)
)
}
private DataFlow::CallNode getEncryptionApplication(
DataFlow::Node input, CryptographicAlgorithm algorithm
) {
private API::CallNode getEncryptionApplication(API::Node input, CryptographicAlgorithm algorithm) {
/*
* ```
* var CryptoJS = require("crypto-js");
@@ -282,13 +302,11 @@ private module CryptoJS {
* Also matches where `CryptoJS.<algorithmName>` has been replaced by `require("crypto-js/<algorithmName>")`
*/
result = getAlgorithmNode(algorithm).getAMemberCall("encrypt") and
input = result.getArgument(0)
result = getAlgorithmNode(algorithm).getMember("encrypt").getACall() and
input = result.getParameter(0)
}
private DataFlow::CallNode getDirectApplication(
DataFlow::Node input, CryptographicAlgorithm algorithm
) {
private API::CallNode getDirectApplication(API::Node input, CryptographicAlgorithm algorithm) {
/*
* ```
* var CryptoJS = require("crypto-js");
@@ -304,11 +322,11 @@ private module CryptoJS {
*/
result = getAlgorithmNode(algorithm).getACall() and
input = result.getArgument(0)
input = result.getParameter(0)
}
private class Apply extends CryptographicOperation {
DataFlow::Node input;
private class Apply extends CryptographicOperation::Range instanceof API::CallNode {
API::Node input;
CryptographicAlgorithm algorithm; // non-functional
Apply() {
@@ -316,22 +334,41 @@ private module CryptoJS {
this = getDirectApplication(input, algorithm)
}
override DataFlow::Node getInput() { result = input }
override DataFlow::Node getAnInput() { result = input.asSink() }
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
// e.g. CryptoJS.AES.encrypt("msg", "key", { mode: CryptoJS.mode.<modeString> })
private BlockMode getExplicitBlockMode() {
exists(string modeString |
API::moduleImport("crypto-js").getMember("mode").getMember(modeString).asSource() =
super.getParameter(2).getMember("mode").asSink()
|
result.matchesString(modeString)
)
}
override BlockMode getBlockMode() {
isBlockEncryptionAlgorithm(this.getAlgorithm()) and
(
if exists(this.getExplicitBlockMode())
then result = this.getExplicitBlockMode()
else
// CBC is the default if not explicitly specified
result = "CBC"
)
}
}
private class Key extends CryptographicKey {
Key() {
exists(DataFlow::SourceNode e, CryptographicAlgorithm algorithm |
e = getAlgorithmNode(algorithm)
|
exists(API::Node e, CryptographicAlgorithm algorithm | e = getAlgorithmNode(algorithm) |
exists(string name |
name = "encrypt" or
name = "decrypt"
|
algorithm instanceof EncryptionAlgorithm and
this = e.getAMemberCall(name).getArgument(1)
this = e.getMember(name).getACall().getArgument(1)
)
or
algorithm instanceof HashingAlgorithm and
@@ -374,7 +411,7 @@ private module CryptoJS {
* A model of the TweetNaCl library.
*/
private module TweetNaCl {
private class Apply extends CryptographicOperation instanceof DataFlow::CallNode {
private class Apply extends CryptographicOperation::Range instanceof DataFlow::CallNode {
DataFlow::Node input;
CryptographicAlgorithm algorithm;
@@ -401,9 +438,12 @@ private module TweetNaCl {
)
}
override DataFlow::Node getInput() { result = input }
override DataFlow::Node getAnInput() { result = input }
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
// No block ciphers implemented
override BlockMode getBlockMode() { none() }
}
}
@@ -434,7 +474,7 @@ private module HashJs {
)
}
private class Apply extends CryptographicOperation instanceof DataFlow::CallNode {
private class Apply extends CryptographicOperation::Range instanceof DataFlow::CallNode {
DataFlow::Node input;
CryptographicAlgorithm algorithm; // non-functional
@@ -456,9 +496,12 @@ private module HashJs {
input = super.getArgument(0)
}
override DataFlow::Node getInput() { result = input }
override DataFlow::Node getAnInput() { result = input }
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
// not relevant for hash.js
override BlockMode getBlockMode() { none() }
}
}
@@ -478,19 +521,20 @@ private module Forge {
private class KeyCipher extends Cipher {
DataFlow::Node key;
CryptographicAlgorithm algorithm; // non-functional
private string blockModeString;
KeyCipher() {
exists(DataFlow::SourceNode mod, string algorithmName |
mod = getAnImportNode() and
algorithm.matchesName(algorithmName)
|
exists(string createName, string cipherName, string cipherPrefix, string cipherSuffix |
exists(string createName, string cipherName, string cipherPrefix |
// `require('forge').cipher.createCipher("3DES-CBC").update("secret", "key");`
(createName = "createCipher" or createName = "createDecipher") and
this = mod.getAPropertyRead("cipher").getAMemberCall(createName) and
this.getArgument(0).mayHaveStringValue(cipherName) and
cipherName = cipherPrefix + "-" + cipherSuffix and
cipherSuffix = ["CBC", "CFB", "CTR", "ECB", "GCM", "OFB"] and
cipherName = cipherPrefix + "-" + blockModeString and
blockModeString = ["CBC", "CFB", "CTR", "ECB", "GCM", "OFB"] and
algorithmName = cipherPrefix and
key = this.getArgument(1)
)
@@ -500,7 +544,8 @@ private module Forge {
createName = "createEncryptionCipher" or createName = "createDecryptionCipher"
|
this = mod.getAPropertyRead(algorithmName).getAMemberCall(createName) and
key = this.getArgument(0)
key = this.getArgument(0) and
blockModeString = algorithmName
)
)
}
@@ -508,6 +553,11 @@ private module Forge {
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
DataFlow::Node getKey() { result = key }
BlockMode getBlockMode() {
isBlockEncryptionAlgorithm(this.getAlgorithm()) and
result.matchesString(blockModeString)
}
}
private class NonKeyCipher extends Cipher {
@@ -527,21 +577,22 @@ private module Forge {
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
}
private class Apply extends CryptographicOperation instanceof DataFlow::CallNode {
private class Apply extends CryptographicOperation::Range instanceof DataFlow::CallNode {
DataFlow::Node input;
CryptographicAlgorithm algorithm; // non-functional
private Cipher cipher;
Apply() {
exists(Cipher cipher |
this = cipher.getAMemberCall("update") and
super.getArgument(0) = input and
algorithm = cipher.getAlgorithm()
)
this = cipher.getAMemberCall("update") and
super.getArgument(0) = input and
algorithm = cipher.getAlgorithm()
}
override DataFlow::Node getInput() { result = input }
override DataFlow::Node getAnInput() { result = input }
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
override BlockMode getBlockMode() { result = cipher.(KeyCipher).getBlockMode() }
}
private class Key extends CryptographicKey {
@@ -586,7 +637,7 @@ private module Forge {
* A model of the md5 library.
*/
private module Md5 {
private class Apply extends CryptographicOperation instanceof DataFlow::CallNode {
private class Apply extends CryptographicOperation::Range instanceof DataFlow::CallNode {
DataFlow::Node input;
CryptographicAlgorithm algorithm;
@@ -600,9 +651,12 @@ private module Md5 {
)
}
override DataFlow::Node getInput() { result = input }
override DataFlow::Node getAnInput() { result = input }
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
// not relevant for md5
override BlockMode getBlockMode() { none() }
}
}
@@ -610,7 +664,7 @@ private module Md5 {
* A model of the bcrypt, bcryptjs, bcrypt-nodejs libraries.
*/
private module Bcrypt {
private class Apply extends CryptographicOperation instanceof DataFlow::CallNode {
private class Apply extends CryptographicOperation::Range instanceof DataFlow::CallNode {
DataFlow::Node input;
CryptographicAlgorithm algorithm;
@@ -633,9 +687,12 @@ private module Bcrypt {
)
}
override DataFlow::Node getInput() { result = input }
override DataFlow::Node getAnInput() { result = input }
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
// not relevant for bcrypt
override BlockMode getBlockMode() { none() }
}
}
@@ -643,7 +700,7 @@ private module Bcrypt {
* A model of the hasha library.
*/
private module Hasha {
private class Apply extends CryptographicOperation instanceof DataFlow::CallNode {
private class Apply extends CryptographicOperation::Range instanceof DataFlow::CallNode {
DataFlow::Node input;
CryptographicAlgorithm algorithm;
@@ -659,9 +716,12 @@ private module Hasha {
)
}
override DataFlow::Node getInput() { result = input }
override DataFlow::Node getAnInput() { result = input }
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
// not relevant for hasha
override BlockMode getBlockMode() { none() }
}
}

View File

@@ -45,8 +45,12 @@ module Cryptography {
/**
* Gets the block mode used to perform this cryptographic operation.
* This may have no result - for example if the `CryptographicAlgorithm` used
* is a stream cipher rather than a block cipher.
*
* This predicate is only expected to have a result if two conditions hold:
* 1. The operation is an encryption operation, i.e. the algorithm used is an `EncryptionAlgorithm`, and
* 2. The algorithm used is a block cipher (not a stream cipher).
*
* If either of these conditions do not hold, then this predicate should have no result.
*/
BlockMode getBlockMode() { result = super.getBlockMode() }
}
@@ -69,8 +73,12 @@ module Cryptography {
/**
* Gets the block mode used to perform this cryptographic operation.
* This may have no result - for example if the `CryptographicAlgorithm` used
* is a stream cipher rather than a block cipher.
*
* This predicate is only expected to have a result if two conditions hold:
* 1. The operation is an encryption operation, i.e. the algorithm used is an `EncryptionAlgorithm`, and
* 2. The algorithm used is a block cipher (not a stream cipher).
*
* If either of these conditions do not hold, then this predicate should have no result.
*/
abstract BlockMode getBlockMode();
}
@@ -92,6 +100,10 @@ module Cryptography {
/** Holds if this block mode is considered to be insecure. */
predicate isWeak() { this = "ECB" }
/** Holds if the given string appears to match this block mode. */
bindingset[s]
predicate matchesString(string s) { s.toUpperCase().matches("%" + this + "%") }
}
}

View File

@@ -26,6 +26,26 @@ private newtype TCryptographicAlgorithm =
isWeakPasswordHashingAlgorithm(name) and isWeak = true
}
/**
* Gets the most specific `CryptographicAlgorithm` that matches the given `name`.
* A matching algorithm is one where the name of the algorithm matches the start of name, with allowances made for different name formats.
* In the case that multiple `CryptographicAlgorithm`s match the given `name`, the algorithm(s) with the longest name will be selected. This is intended to select more specific versions of algorithms when multiple versions could match - for example "SHA3_224" matches against both "SHA3" and "SHA3224", but the latter is a more precise match.
*/
bindingset[name]
private CryptographicAlgorithm getBestAlgorithmForName(string name) {
result =
max(CryptographicAlgorithm algorithm |
algorithm.getName() =
[
name.toUpperCase(), // the full name
name.toUpperCase().regexpCapture("^([\\w]+)(?:-.*)?$", 1), // the name prior to any dashes or spaces
name.toUpperCase().regexpCapture("^([A-Z0-9]+)(?:(-|_).*)?$", 1) // the name prior to any dashes, spaces, or underscores
].regexpReplaceAll("[-_ ]", "") // strip dashes, underscores, and spaces
|
algorithm order by algorithm.getName().length()
)
}
/**
* A cryptographic algorithm.
*/
@@ -39,15 +59,11 @@ abstract class CryptographicAlgorithm extends TCryptographicAlgorithm {
abstract string getName();
/**
* Holds if the name of this algorithm matches `name` modulo case,
* white space, dashes, underscores, and anything after a dash in the name
* (to ignore modes of operation, such as CBC or ECB).
* Holds if the name of this algorithm is the most specific match for `name`.
* This predicate matches quite liberally to account for different ways of formatting algorithm names, e.g. using dashes, underscores, or spaces as separators, including or not including block modes of operation, etc.
*/
bindingset[name]
predicate matchesName(string name) {
[name.toUpperCase(), name.toUpperCase().regexpCapture("^(\\w+)(?:-.*)?$", 1)]
.regexpReplaceAll("[-_ ]", "") = getName()
}
predicate matchesName(string name) { this = getBestAlgorithmForName(name) }
/**
* Holds if this algorithm is weak.

View File

@@ -41,7 +41,7 @@ module BrokenCryptoAlgorithm {
WeakCryptographicOperationSink() {
exists(CryptographicOperation application |
application.getAlgorithm().isWeak() and
this = application.getInput()
this = application.getAnInput()
)
}
}

View File

@@ -47,7 +47,7 @@ module InsufficientPasswordHash {
application.getAlgorithm().isWeak() or
not application.getAlgorithm() instanceof PasswordHashingAlgorithm
|
this = application.getInput()
this = application.getAnInput()
)
}
}

View File

@@ -1,10 +1,12 @@
| tst.js:5:26:5:42 | keypair.secretKey |
| tst.js:19:42:19:51 | 'a secret' |
| tst.js:29:36:29:51 | 'secret key 123' |
| tst.js:32:26:32:30 | "Key" |
| tst.js:35:30:35:34 | "Key" |
| tst.js:37:48:37:63 | 'secret key 123' |
| tst.js:39:38:39:42 | "Key" |
| tst.js:57:45:57:47 | key |
| tst.js:59:50:59:52 | key |
| tst.js:73:32:73:39 | "secret" |
| tst.js:3:34:3:36 | key |
| tst.js:7:26:7:42 | keypair.secretKey |
| tst.js:21:42:21:51 | 'a secret' |
| tst.js:36:36:36:51 | 'secret key 123' |
| tst.js:39:26:39:30 | "Key" |
| tst.js:42:30:42:34 | "Key" |
| tst.js:44:48:44:63 | 'secret key 123' |
| tst.js:46:38:46:42 | "Key" |
| tst.js:50:29:50:33 | "key" |
| tst.js:68:45:68:47 | key |
| tst.js:70:50:70:52 | key |
| tst.js:84:32:84:39 | "secret" |

View File

@@ -1,31 +1,35 @@
| tst.js:1:1:1:27 | asmCryp ... (input) | SHA256 | tst.js:1:22:1:26 | input |
| tst.js:5:5:5:43 | jwcrypt ... retKey) | DSA | tst.js:5:19:5:23 | input |
| tst.js:10:18:10:55 | cipher. ... 'hex') | AES192 | tst.js:10:32:10:39 | 'input1' |
| tst.js:11:18:11:54 | cipher. ... 'hex') | AES192 | tst.js:11:31:11:38 | 'input2' |
| tst.js:15:1:15:21 | hash.up ... nput1') | SHA256 | tst.js:15:13:15:20 | 'input1' |
| tst.js:16:1:16:20 | hash.write('input2') | SHA256 | tst.js:16:12:16:19 | 'input2' |
| tst.js:20:1:20:21 | hmac.up ... nput1') | SHA256 | tst.js:20:13:20:20 | 'input1' |
| tst.js:21:1:21:20 | hmac.write('input2') | SHA256 | tst.js:21:12:21:19 | 'input2' |
| tst.js:25:1:25:21 | sign.up ... nput1') | SHA256 | tst.js:25:13:25:20 | 'input1' |
| tst.js:26:1:26:20 | sign.write('input2') | SHA256 | tst.js:26:12:26:19 | 'input2' |
| tst.js:29:1:29:52 | CryptoJ ... y 123') | AES | tst.js:29:22:29:33 | 'my message' |
| tst.js:32:1:32:31 | CryptoJ ... "Key") | SHA1 | tst.js:32:15:32:23 | "Message" |
| tst.js:35:1:35:35 | CryptoJ ... "Key") | SHA1 | tst.js:35:19:35:27 | "Message" |
| tst.js:37:1:37:64 | require ... y 123') | AES | tst.js:37:34:37:45 | 'my message' |
| tst.js:39:1:39:43 | require ... "Key") | SHA1 | tst.js:39:27:39:35 | "Message" |
| tst.js:41:1:41:34 | require ... ssage') | ED25519 | tst.js:41:22:41:33 | 'my message' |
| tst.js:43:1:43:34 | require ... ssage') | SHA512 | tst.js:43:22:43:33 | 'my message' |
| tst.js:45:1:45:39 | require ... ssage') | ED25519 | tst.js:45:27:45:38 | 'my message' |
| tst.js:47:1:47:39 | require ... ssage') | SHA512 | tst.js:47:27:47:38 | 'my message' |
| tst.js:49:1:49:41 | require ... ('abc') | SHA256 | tst.js:49:36:49:40 | 'abc' |
| tst.js:51:1:51:51 | require ... ('abc') | SHA512 | tst.js:51:46:51:50 | 'abc' |
| tst.js:53:1:53:86 | require ... y dog') | MD5 | tst.js:53:41:53:85 | 'The qu ... zy dog' |
| tst.js:55:1:55:91 | require ... y dog') | MD5 | tst.js:55:46:55:90 | 'The qu ... zy dog' |
| tst.js:57:1:57:65 | require ... ecret") | RC2 | tst.js:57:57:57:64 | "secret" |
| tst.js:59:1:59:70 | require ... ecret") | 3DES | tst.js:59:62:59:69 | "secret" |
| tst.js:61:1:61:25 | require ... ssage") | MD5 | tst.js:61:16:61:24 | "message" |
| tst.js:63:1:63:32 | require ... ssword) | BCRYPT | tst.js:63:24:63:31 | password |
| tst.js:65:1:65:36 | require ... ssword) | BCRYPT | tst.js:65:28:65:35 | password |
| tst.js:67:1:67:34 | require ... ssword) | BCRYPT | tst.js:67:26:67:33 | password |
| tst.js:69:1:69:39 | require ... ssword) | BCRYPT | tst.js:69:31:69:38 | password |
| tst.js:71:1:71:49 | require ... md5" }) | MD5 | tst.js:71:18:71:26 | 'unicorn' |
| tst.js:1:1:1:27 | asmCryp ... (input) | SHA256 | tst.js:1:22:1:26 | input | <none> |
| tst.js:3:1:3:41 | asmCryp ... ey, iv) | AES | tst.js:3:27:3:31 | input | OFB |
| tst.js:7:5:7:43 | jwcrypt ... retKey) | DSA | tst.js:7:19:7:23 | input | <none> |
| tst.js:12:18:12:55 | cipher. ... 'hex') | AES192 | tst.js:12:32:12:39 | 'input1' | CBC |
| tst.js:13:18:13:54 | cipher. ... 'hex') | AES192 | tst.js:13:31:13:38 | 'input2' | CBC |
| tst.js:17:1:17:21 | hash.up ... nput1') | SHA256 | tst.js:17:13:17:20 | 'input1' | <none> |
| tst.js:18:1:18:20 | hash.write('input2') | SHA256 | tst.js:18:12:18:19 | 'input2' | <none> |
| tst.js:22:1:22:21 | hmac.up ... nput1') | SHA256 | tst.js:22:13:22:20 | 'input1' | <none> |
| tst.js:23:1:23:20 | hmac.write('input2') | SHA256 | tst.js:23:12:23:19 | 'input2' | <none> |
| tst.js:27:1:27:21 | sign.up ... nput1') | SHA256 | tst.js:27:13:27:20 | 'input1' | <none> |
| tst.js:28:1:28:20 | sign.write('input2') | SHA256 | tst.js:28:12:28:19 | 'input2' | <none> |
| tst.js:32:1:32:38 | cipher. ... 'hex') | AES | tst.js:32:15:32:22 | 'input1' | ECB |
| tst.js:33:1:33:37 | cipher. ... 'hex') | AES | tst.js:33:14:33:21 | 'input2' | ECB |
| tst.js:36:1:36:52 | CryptoJ ... y 123') | AES | tst.js:36:22:36:33 | 'my message' | CBC |
| tst.js:39:1:39:31 | CryptoJ ... "Key") | SHA1 | tst.js:39:15:39:23 | "Message" | <none> |
| tst.js:42:1:42:35 | CryptoJ ... "Key") | SHA1 | tst.js:42:19:42:27 | "Message" | <none> |
| tst.js:44:1:44:64 | require ... y 123') | AES | tst.js:44:34:44:45 | 'my message' | CBC |
| tst.js:46:1:46:43 | require ... "Key") | SHA1 | tst.js:46:27:46:35 | "Message" | <none> |
| tst.js:50:1:50:40 | CryptoJ ... , opts) | AES | tst.js:50:22:50:26 | "msg" | CFB |
| tst.js:52:1:52:34 | require ... ssage') | ED25519 | tst.js:52:22:52:33 | 'my message' | <none> |
| tst.js:54:1:54:34 | require ... ssage') | SHA512 | tst.js:54:22:54:33 | 'my message' | <none> |
| tst.js:56:1:56:39 | require ... ssage') | ED25519 | tst.js:56:27:56:38 | 'my message' | <none> |
| tst.js:58:1:58:39 | require ... ssage') | SHA512 | tst.js:58:27:58:38 | 'my message' | <none> |
| tst.js:60:1:60:41 | require ... ('abc') | SHA256 | tst.js:60:36:60:40 | 'abc' | <none> |
| tst.js:62:1:62:51 | require ... ('abc') | SHA512 | tst.js:62:46:62:50 | 'abc' | <none> |
| tst.js:64:1:64:86 | require ... y dog') | MD5 | tst.js:64:41:64:85 | 'The qu ... zy dog' | <none> |
| tst.js:66:1:66:91 | require ... y dog') | MD5 | tst.js:66:46:66:90 | 'The qu ... zy dog' | <none> |
| tst.js:68:1:68:65 | require ... ecret") | RC2 | tst.js:68:57:68:64 | "secret" | <unknown> |
| tst.js:70:1:70:70 | require ... ecret") | 3DES | tst.js:70:62:70:69 | "secret" | CBC |
| tst.js:72:1:72:25 | require ... ssage") | MD5 | tst.js:72:16:72:24 | "message" | <none> |
| tst.js:74:1:74:32 | require ... ssword) | BCRYPT | tst.js:74:24:74:31 | password | <none> |
| tst.js:76:1:76:36 | require ... ssword) | BCRYPT | tst.js:76:28:76:35 | password | <none> |
| tst.js:78:1:78:34 | require ... ssword) | BCRYPT | tst.js:78:26:78:33 | password | <none> |
| tst.js:80:1:80:39 | require ... ssword) | BCRYPT | tst.js:80:31:80:38 | password | <none> |
| tst.js:82:1:82:49 | require ... md5" }) | MD5 | tst.js:82:18:82:26 | 'unicorn' | <none> |

View File

@@ -1,4 +1,16 @@
import javascript
string getBlockMode(CryptographicOperation operation) {
if
operation.getAlgorithm() instanceof EncryptionAlgorithm and
not operation.getAlgorithm().(EncryptionAlgorithm).isStreamCipher()
then
if exists(operation.getBlockMode())
then result = operation.getBlockMode()
else result = "<unknown>"
else result = "<none>"
}
from CryptographicOperation operation
select operation, operation.getAlgorithm().getName(), operation.getInput()
select operation, operation.getAlgorithm().getName(), operation.getAnInput(),
getBlockMode(operation)

View File

@@ -1,5 +1,7 @@
asmCrypto.SHA256.hex(input);
asmCrypto.AES_OFB.encrypt(input, key, iv)
var jwcrypto = require("browserid-crypto");
jwcrypto.generateKeypair({algorithm: 'DSA'}, function(err, keypair) {
jwcrypto.sign(input, keypair.secretKey);
@@ -25,6 +27,11 @@ const sign = crypto.createSign('SHA256');
sign.update('input1');
sign.write('input2');
var crypto = require('crypto');
var cipher = crypto.createCipher('aes-192-ecb', 'a password');
cipher.update('input1', 'utf8', 'hex');
cipher.write('input2', 'utf8', 'hex');
var CryptoJS = require("crypto-js");
CryptoJS.AES.encrypt('my message', 'secret key 123');
@@ -38,6 +45,10 @@ require("crypto-js/aes").encrypt('my message', 'secret key 123');
require("crypto-js/sha1")("Message", "Key");
var CryptoJS = require("crypto-js");
var opts = { mode: CryptoJS.mode.CFB }
CryptoJS.AES.encrypt("msg", "key", opts)
require("nacl").sign('my message');
require("nacl").hash('my message');