/ca update help message and add block cipher parameter

/ca initial SM4 key search implementation

Add SM4 key search test

Refactor cmd_search.c to have common code for key search.
This commit is contained in:
Sylvain Pelissier 2022-09-08 16:01:55 +02:00 committed by pancake
parent ca2674228f
commit 4a01f475f3
10 changed files with 121 additions and 37 deletions

View File

@ -9,6 +9,7 @@ static int cmd_search(void *data, const char *input);
#define USE_EMULATION 1
#define AES_SEARCH_LENGTH 40
#define SM4_SEARCH_LENGTH 24
#define PRIVATE_KEY_SEARCH_LENGTH 11
static const char *help_msg_search_wide_string[] = {
@ -175,7 +176,7 @@ static const char *help_msg_slash_a[] = {
static const char *help_msg_slash_c[] = {
"Usage: /c", "", "Search for crypto materials",
"/ca", "", "search for AES keys expanded in memory",
"/ca", "[?] [algo]", "search for keys expanded in memory",
"/cc", "[algo] [digest]", "find collisions (bruteforce block length values until given checksum is found)",
"/cd", "", "search for ASN1/DER certificates",
"/cg", "", "search for GPG/PGP keys and signatures (Plaintext and binary form)",
@ -243,8 +244,8 @@ struct search_parameters {
PJ *pj;
int outmode; // 0 or R_MODE_RADARE or R_MODE_JSON
bool inverse;
bool aes_search;
bool privkey_search;
bool key_search;
int key_search_len;
int c; // used for progress
};
@ -2618,8 +2619,8 @@ static void do_string_search(RCore *core, RInterval search_itv, struct search_pa
if (r_cons_is_breaked ()) {
break;
}
RSearchKeyword *kw = r_list_first (core->search->kws);
if (param->outmode != R_MODE_JSON) {
RSearchKeyword *kw = r_list_first (core->search->kws);
int lenstr = kw? kw->keyword_length: 0;
const char *bytestr = lenstr > 1? "bytes": "byte";
eprintf ("Searching %d %s in [0x%"PFMT64x "-0x%"PFMT64x "]\n",
@ -2662,15 +2663,10 @@ static void do_string_search(RCore *core, RInterval search_itv, struct search_pa
(void)r_io_read_at (core->io, at, buf, len);
}
r_search_update (core->search, at, buf, len);
if (param->aes_search) {
if (param->key_search) {
// Adjust length to search between blocks.
if (len == core->blocksize) {
len -= AES_SEARCH_LENGTH - 1;
}
} else if (param->privkey_search) {
// Adjust length to search between blocks.
if (len == core->blocksize) {
len -= PRIVATE_KEY_SEARCH_LENGTH - 1;
len -= param->key_search_len - 1;
}
}
if (core->search->maxhits > 0 && core->search->nhits >= core->search->maxhits) {
@ -3298,8 +3294,8 @@ static int cmd_search(void *data, const char *input) {
.cmd_hit = r_config_get (core->config, "cmd.hit"),
.outmode = 0,
.inverse = false,
.aes_search = false,
.privkey_search = false,
.key_search = false,
.key_search_len = 0,
.c = 0,
};
if (!param.cmd_hit) {
@ -3836,16 +3832,39 @@ reread:
case 'a': // "/ca"
{
RSearchKeyword *kw;
if (input[2] == 'j') {
param.outmode = R_MODE_JSON;
char *space = strchr (input, ' ');
const char *arg = space? r_str_trim_head_ro (space + 1): NULL;
if (!arg || *(space - 1) == '?') {
eprintf ("Usage: /ca [algo]\n");
eprintf ("Currently supported block ciphers:\n");
eprintf (" aes\n");
eprintf (" sm4\n");
goto beach;
} else {
kw = r_search_keyword_new_hexmask ("00", NULL);
if (input[2] == 'j') {
param.outmode = R_MODE_JSON;
}
if (!strcmp (arg, "aes")) {
// AES search is done over 40 bytes
param.key_search_len = AES_SEARCH_LENGTH;
r_search_reset (core->search, R_SEARCH_AES);
} else if (!strcmp (arg, "sm4")) {
param.key_search_len = SM4_SEARCH_LENGTH;
r_search_reset (core->search, R_SEARCH_SM4);
} else {
eprintf ("Unsupported block ciphers: %s\n", arg);
goto beach;
}
if (core->blocksize < param.key_search_len) {
eprintf ("Block size must be bigger than %d bytes for the search\n", param.key_search_len);
goto beach;
}
r_search_kw_add (search, kw);
r_search_begin (core->search);
param.key_search = true;
}
kw = r_search_keyword_new_hexmask ("00", NULL);
// AES search is done over 40 bytes
kw->keyword_length = AES_SEARCH_LENGTH;
r_search_reset (core->search, R_SEARCH_AES);
r_search_kw_add (search, kw);
r_search_begin (core->search);
param.aes_search = true;
break;
}
case 'r': // "/cr"
@ -3860,7 +3879,7 @@ reread:
r_search_reset (core->search, R_SEARCH_PRIV_KEY);
r_search_kw_add (search, kw);
r_search_begin (core->search);
param.privkey_search = true;
param.key_search = true;
break;
}
default: {

View File

@ -5,6 +5,7 @@
* */
#include <r_crypto.h>
#include <r_crypto/r_sm4.h>
#include <r_util.h>
#include <memory.h>
@ -17,14 +18,6 @@
/* Family Key FK */
static const ut32 FK[4] = { 0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc };
/* Constant Key CK */
static const ut32 CK[32] = {
0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269, 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249, 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229, 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279
};
/* SM4 S-boxes */
static const ut8 Sbox[256] = {
0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,
@ -46,7 +39,7 @@ static const ut8 Sbox[256] = {
};
/* Calculating next round keys */
static ut32 sm4_RK(ut32 rk) {
R_API ut32 sm4_RK(ut32 rk) {
ut8 a[4];
ut8 b[4];
ut32 lb = 0;
@ -125,7 +118,7 @@ static bool sm4_init(RCryptoJob *cj, ut32 *sk, const ut8 *key, int keylen, int d
k[2] = MK[2] ^ FK[2];
k[3] = MK[3] ^ FK[3];
for (i = 0; i < 32; i++) {
k[i + 4] = k[i] ^ (sm4_RK (k[i + 1] ^ k[i + 2] ^ k[i + 3] ^ CK[i]));
k[i + 4] = k[i] ^ (sm4_RK (k[i + 1] ^ k[i + 2] ^ k[i + 3] ^ sm4_CK[i]));
if (dir == 0) {
cj->sm4_sk[i] = k[i + 4];

View File

@ -0,0 +1,24 @@
#ifndef R_SM4_H
#define R_SM4_H
#include <r_util.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Constant Key CK */
static const ut32 sm4_CK[32] = {
0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269, 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249, 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229, 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279
};
R_API ut32 sm4_RK(ut32 rk);
#ifdef __cplusplus
}
#endif
#endif // R_SM4_H

View File

@ -21,6 +21,7 @@ enum {
R_SEARCH_STRING,
R_SEARCH_XREFS,
R_SEARCH_AES,
R_SEARCH_SM4,
R_SEARCH_PRIV_KEY,
R_SEARCH_DELTAKEY,
R_SEARCH_MAGIC,

View File

@ -1,7 +1,7 @@
include ../config.mk
NAME=r_search
OBJS=search.o bytepat.o strings.o aes_find.o privkey_find.o
OBJS=search.o bytepat.o strings.o aes_find.o privkey_find.o sm4_find.o
OBJS+=regexp.o keyword.o uds.o rabin_karp.o
# OBJ+=rsakey.o
R2DEPS=r_util

View File

@ -7,6 +7,7 @@ r_search_sources = [
'privkey_find.c',
'rabin_karp.c',
'search.c',
'sm4_find.c',
'strings.c'
]

View File

@ -85,6 +85,7 @@ R_API int r_search_set_mode(RSearch *s, int mode) {
case R_SEARCH_KEYWORD: s->update = search_kw_update; break;
case R_SEARCH_REGEXP: s->update = search_regexp_update; break;
case R_SEARCH_AES: s->update = search_aes_update; break;
case R_SEARCH_SM4: s->update = search_sm4_update; break;
case R_SEARCH_PRIV_KEY: s->update = search_privkey_update; break;
case R_SEARCH_STRING: s->update = search_strings_update; break;
case R_SEARCH_DELTAKEY: s->update = search_deltakey_update; break;

View File

@ -1,6 +1,7 @@
// To keep update function out of public r_search API
R_IPI int search_kw_update(RSearch *s, ut64 from, const ut8 *buf, int len);
R_IPI int search_aes_update(RSearch *s, ut64 from, const ut8 *buf, int len);
R_IPI int search_sm4_update(RSearch *s, ut64 from, const ut8 *buf, int len);
R_IPI int search_privkey_update(RSearch *s, ut64 from, const ut8 *buf, int len);
R_IPI int search_deltakey_update(RSearch *s, ut64 from, const ut8 *buf, int len);
R_IPI int search_strings_update(RSearch *s, ut64 from, const ut8 *buf, int len);

36
libr/search/sm4_find.c Normal file
View File

@ -0,0 +1,36 @@
/* radare2 - LGPL - Copyright 2022 - Sylvain Pelissier */
#include <r_crypto/r_sm4.h>
#include <r_search.h>
#include <r_util.h>
#define SM4_SEARCH_LENGTH 24
#define SM4_KEY_LENGTH 16
static bool sm4_key_test(const unsigned char *buf) {
ut32 *ptr = (ut32 *)buf;
return (ptr[4] == (ptr[0] ^ (sm4_RK (ptr[1] ^ ptr[2] ^ ptr[3] ^ sm4_CK[4])))) && (ptr[5] == (ptr[1] ^ (sm4_RK (ptr[2] ^ ptr[3] ^ ptr[4] ^ sm4_CK[5]))));
}
R_IPI int search_sm4_update(RSearch *s, ut64 from, const ut8 *buf, int len) {
int i, t, last = len - SM4_SEARCH_LENGTH;
RListIter *iter;
RSearchKeyword *kw;
const int old_nhits = s->nhits;
r_list_foreach (s->kws, iter, kw) {
for (i = 0; i < last + 1; i++) {
if (sm4_key_test (buf + i)) {
kw->keyword_length = SM4_KEY_LENGTH;
t = r_search_hit_new (s, kw, from + i);
if (!t) {
return -1;
}
if (t > 1) {
return s->nhits - old_nhits;
}
i += SM4_SEARCH_LENGTH;
}
}
}
return -1;
}

View File

@ -1,6 +1,6 @@
NAME=cmd.hit for /ca
FILE=bins/other/aes.dump
CMDS=/ca
CMDS=/ca aes
EXPECT=<<EOF
0x0000001e hit0_0 0000000000000000000000000000000000000000000000000000000000000000
EOF
@ -8,15 +8,23 @@ RUN
NAME=cmd.hit for /ca
FILE=bins/other/aes_192.dump
CMDS=/ca
CMDS=/ca aes
EXPECT=<<EOF
0x000000fa hit0_0 000102030405060708090a0b0c0d0e0f1011121314151617
EOF
RUN
NAME=cmd.hit for /ca sm4
FILE=bins/other/sm4_key_schedule.bin
CMDS=/ca sm4
EXPECT=<<EOF
0x000000ff hit0_0 f98621f1612b6641db28e44757dbe32c
EOF
RUN
NAME=cmd.hit for /caj
FILE=bins/other/aes_192.dump
CMDS=/caj
CMDS=/caj aes
EXPECT=<<EOF
[{"offset":250,"type":"hexpair","data":"000102030405060708090a0b0c0d0e0f1011121314151617"}]
EOF