Skip to content

Commit 3c6f318

Browse files
committed
C++: Add query tests.
1 parent b0514de commit 3c6f318

File tree

4 files changed

+208
-0
lines changed

4 files changed

+208
-0
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
| tests_crypto.cpp:11:6:11:18 | encryptString | This may be a custom implementation of a cryptographic primitive. |
2+
| tests_crypto.cpp:30:6:30:14 | MyEncrypt | This may be a custom implementation of a cryptographic primitive. |
3+
| tests_crypto.cpp:83:6:83:18 | init_aes_sbox | This may be a custom implementation of a cryptographic primitive. |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
experimental/Security/CWE/CWE-1240/CustomCryptographicPrimitive.ql
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// Cryptography snippets. All (non-stub) functions in this file should be flagged by the query.
2+
3+
typedef unsigned char uint8_t;
4+
5+
int strlen(const char *string);
6+
7+
// ---
8+
9+
// the following function is homebrew crypto written for this test. This is a bad algorithm
10+
// on multiple levels and should never be used in cryptography.
11+
void encryptString(char *string, unsigned int key) {
12+
char *ptr = string;
13+
int len = strlen(string);
14+
15+
while (len >= 4) {
16+
// encrypt block by XOR-ing with the key
17+
ptr[0] = ptr[0] ^ (key >> 0);
18+
ptr[1] = ptr[1] ^ (key >> 8);
19+
ptr[2] = ptr[2] ^ (key >> 16);
20+
ptr[3] = ptr[3] ^ (key >> 24);
21+
22+
// move on
23+
ptr += 4;
24+
len -= 4;
25+
}
26+
}
27+
28+
// the following function is homebrew crypto written for this test. This is a bad algorithm
29+
// on multiple levels and should never be used in cryptography.
30+
void MyEncrypt(const unsigned int *dataIn, unsigned int *dataOut, unsigned int dataSize, unsigned int key[2]) {
31+
unsigned int state[2];
32+
unsigned int t;
33+
34+
state[0] = key[0];
35+
state[1] = key[1];
36+
37+
for (unsigned int i = 0; i < dataSize; i++) {
38+
// mix state
39+
t = state[0];
40+
state[0] = (state[0] << 1) | (state[1] >> 31);
41+
state[1] = (state[1] << 1) | (t >> 31);
42+
43+
// encrypt data
44+
dataOut[i] = dataIn[i] ^ state[0];
45+
}
46+
}
47+
48+
// the following function resembles an implementation of the AES "mix columns"
49+
// step. It is not accurate, efficient or safe and should never be used in
50+
// cryptography.
51+
void mix_columns(const uint8_t inputs[4], uint8_t outputs[4]) {
52+
// The "mix columns" step takes four bytes as inputs. Each byte represents a
53+
// polynomial with 8 one-bit coefficients, e.g. input bits 00001101
54+
// represent the polynomial x^3 + x^2 + 1. Arithmetic is reduced modulo
55+
// x^8 + x^4 + x^3 + x + 1 (= 0x11b).
56+
//
57+
// The "mix columns" step multiplies each input by 2 (in the field described
58+
// above) to produce four more values. The output is then four values
59+
// produced by XOR-ing specific combinations of five of these eight values.
60+
// The exact values selected here do not match the actual AES algorithm.
61+
//
62+
// We avoid control flow decisions that depend on the inputs.
63+
uint8_t vs[4];
64+
65+
vs[0] = inputs[0] << 1; // multiply by two
66+
vs[0] ^= (inputs[0] >> 7) * 0x1b; // reduce modulo 0x11b; the top bit was removed in the shift.
67+
vs[1] = inputs[1] << 1;
68+
vs[1] ^= (inputs[1] >> 7) * 0x1b;
69+
vs[2] = inputs[2] << 1;
70+
vs[2] ^= (inputs[2] >> 7) * 0x1b;
71+
vs[3] = inputs[3] << 1;
72+
vs[3] ^= (inputs[3] >> 7) * 0x1b;
73+
74+
outputs[0] = inputs[0] ^ inputs[1] ^ inputs[2] ^ vs[0] ^ vs[1];
75+
outputs[1] = inputs[1] ^ inputs[2] ^ inputs[3] ^ vs[1] ^ vs[2];
76+
outputs[2] = inputs[2] ^ inputs[3] ^ inputs[0] ^ vs[2] ^ vs[3];
77+
outputs[3] = inputs[3] ^ inputs[0] ^ inputs[1] ^ vs[3] ^ vs[0];
78+
}
79+
80+
// the following function resembles initialization of an S-box as may be done
81+
// in an implementation of DES, AES and other encryption algorithms. It is not
82+
// accurate, efficient or safe and should never be used in cryptography.
83+
void init_aes_sbox(unsigned char data[256]) {
84+
// initialize `data` in a loop using lots of ^, ^= and << operations and
85+
// a few fixed constants.
86+
unsigned int state = 0x12345678;
87+
88+
for (int i = 0; i < 256; i++)
89+
{
90+
state ^= (i ^ 0x86) << 24;
91+
state ^= (i ^ 0xb9) << 16;
92+
state ^= (i ^ 0x11) << 8;
93+
state ^= (i ^ 0x23) << 0;
94+
state = (state << 1) ^ (state >> 31);
95+
data[i] = state & 0xff;
96+
}
97+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// Non-cryptography snippets. Nothing in this file should be flagged by the query.
2+
3+
typedef unsigned char uint8_t;
4+
typedef unsigned int uint32_t;
5+
typedef unsigned long size_t;
6+
7+
// a very cut down stub for `std::cout`
8+
namespace std
9+
{
10+
template<class charT> struct char_traits;
11+
12+
template <class charT, class traits = char_traits<charT> >
13+
class basic_ostream {
14+
public:
15+
typedef charT char_type;
16+
};
17+
template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const charT*);
18+
19+
typedef basic_ostream<char> ostream;
20+
21+
extern ostream cout;
22+
}
23+
24+
// ---
25+
26+
uint32_t lookup[256];
27+
28+
uint8_t computeCRC32(const uint8_t *data, size_t dataLen) {
29+
// This function has "RC3" in its name, but is not an implementation of the (broken) RC3 encryption algorithm.
30+
uint32_t result = 0xFFFFFFFF;
31+
32+
for (size_t i = 0; i < dataLen; i++) {
33+
result = (result >> 8) + lookup[(result ^ data[i]) & 0xFF];
34+
result = (result >> 8) + lookup[(result ^ data[i]) & 0xFF]; // artificial extra compute
35+
result = (result >> 8) + lookup[(result ^ data[i]) & 0xFF]; // artificial extra compute
36+
result = (result >> 8) + lookup[(result ^ data[i]) & 0xFF]; // artificial extra compute
37+
}
38+
39+
return result ^ 0xFFFFFFFF;
40+
}
41+
42+
void convert_image_universal(uint32_t *img, int width, int height) {
43+
// This function has "rsa" in its name, but is nothing to do with the RSA encryption algorithm.
44+
uint32_t *pixel_ptr = img;
45+
uint32_t num_pixels = width * height;
46+
47+
// convert pixels RGBA -> ARGB (with probably unhelpful loop unrolling)
48+
while (num_pixels >= 4) {
49+
pixel_ptr[0] = (pixel_ptr[0] >> 8) ^ (pixel_ptr[0] << 24);
50+
pixel_ptr[1] = (pixel_ptr[1] >> 8) ^ (pixel_ptr[1] << 24);
51+
pixel_ptr[2] = (pixel_ptr[2] >> 8) ^ (pixel_ptr[2] << 24);
52+
pixel_ptr[3] = (pixel_ptr[3] >> 8) ^ (pixel_ptr[3] << 24);
53+
num_pixels -= 4;
54+
}
55+
if (num_pixels >= 2) {
56+
pixel_ptr[0] = (pixel_ptr[0] >> 8) ^ (pixel_ptr[0] << 24);
57+
pixel_ptr[1] = (pixel_ptr[1] >> 8) ^ (pixel_ptr[1] << 24);
58+
num_pixels -= 2;
59+
}
60+
if (num_pixels >= 1) {
61+
pixel_ptr[2] = (pixel_ptr[2] >> 8) ^ (pixel_ptr[2] << 24);
62+
}
63+
}
64+
65+
const char* yes_no_setting() { return "no"; }
66+
67+
void output_encrypt_decrypt_algorithms() {
68+
// This function has "encrypt" and "decrypt" in its name, but no encryption is done.
69+
// This function uses `<<` heavily, but not as an integer shift left.
70+
const char *indent = " ";
71+
72+
std::cout << "Supported algorithms:\n";
73+
std::cout << indent << "DES (" << yes_no_setting() << ")\n";
74+
std::cout << indent << "3DES (" << yes_no_setting() << ")\n";
75+
std::cout << indent << "AES (" << yes_no_setting() << ")\n";
76+
std::cout << indent << "RSA (" << yes_no_setting() << ")\n";
77+
std::cout << indent << "Blowfish (" << yes_no_setting() << ")\n";
78+
std::cout << indent << "Twofish (" << yes_no_setting() << ")\n";
79+
std::cout << indent << "Chacha (" << yes_no_setting() << ")\n";
80+
}
81+
82+
// this macro expands to some compute operations that look a bit like cryptography
83+
#define COMPUTE(v) \
84+
v[0] ^= v[1] ^ v[2] ^ v[3] ^ v[4]; \
85+
v[1] ^= v[2] ^ v[3] ^ v[4] ^ v[5]; \
86+
v[2] ^= v[3] ^ v[4] ^ v[5] ^ v[6]; \
87+
v[3] ^= v[4] ^ v[5] ^ v[6] ^ v[7];
88+
89+
void wideStringCharsAt(int *v) {
90+
// This function has "des" and "rsa" in the name.
91+
COMPUTE(v)
92+
}
93+
94+
void bitcastVariable(int *v) {
95+
// This function has "aria" and "cast" in the name.
96+
COMPUTE(v)
97+
}
98+
99+
void dividesVariance(int *v) {
100+
// This function has "des" and "aria" in the name.
101+
COMPUTE(v)
102+
}
103+
104+
void broadcastNodes(int *v) {
105+
// This function has "cast" and "des" in the name.
106+
COMPUTE(v)
107+
}

0 commit comments

Comments
 (0)