声明:本文章中所有内容仅供学习交流使用,不用于其他任何目的,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,擅自使用本文讲解的技术而导致的任何意外,作者均不负责,若有侵权,请联系作者立即删除!
介绍:随着越来越多的人都会白盒AES的DFA,现在一些厂商为了安全性开始使用白盒SM4,那就让我们来看看吧~
包名:Y29tLmJ5ZC5kZW56YWRpbGluaw==
版本号:3.1.8
定位也比较简单,相信屏幕前的彦祖都可以找到,这里直接给出Frida的脚本了
然后我们使用Unidbg去模拟执行,代码如下
arg3其实很明显就是IV了,看不出来也没关系,So里面可以看得出来,这里要用readFile的形式来读取它这个白盒的表,表太大了不能直接定义为字符串所以我采用了这种方式
然后运行,发现读取了maps,补一下,不补的话跑不起来
然后继续跑,会发现报错了,bangcle crypto tool error code : -1,NullPointerException这个空指针异常是我们没跑完肯定没有结果,然后我们又去读取的结果(getValue)所以报错了
现在来看看这个报错哪来的,因为这个样本没有什么混淆、字符串加密,所以字符串加密就可以直接搜索出来了
大概意思就是v12有问题,不为0,导致的错误,我们进去看看sub_509C这个函数
可以通过断点在几个可疑的地方下一下断点看看到底执行了没有,也可以使用traceCode,我这里就直接说了,其实是v17 = (*((*a1)->reserved0 + 168))(*a1, a6)这里出问题了,根据Unidbg这里是GetStringUTFLength,然后判断长度是不是奇数,是的话就直接-1,-1基本表示失败、有问题,这里读取到的表长度是0x40009,是奇数,这个表按理来说是偶数才对,并且我们看了一下表的长度应该是0x40008才对,不知道什么原因读错了,patch一下就好了,代码如下
然后代码就跑通了,这里要注意如果我们将明文改成几个字节跑出来的结果是错的,所以我上面没有修改明文,估计是在哪里判断了长度,无伤大雅我们继续分析,根据之前的符号已知是CBC模式的,并且IV我们也猜到了可能是其中一个参数,接下来我们就点进伪代码分析一下
最后会跟到这个函数然后就没办法跟下去了,没办法直接根据伪代码来找到白盒SM4的具体位置,造成这个原因是因为IDA的反编译出问题了,其实就在这个函数里面,但是伪代码没翻译出来,对应如下
我是怎么发现的呢一开始?我一开始直接偷懒了,搜索SM4直接定位到了bangcle_WB_QSM4_encrypt
Hook了一下发现确实是这个函数并且代码的实现也确实是查表的实现,并且找不到Key,那就是白盒SM4了
那如果符号搜索不到呢我们又要怎么定位?
我们还可以使用traceCode和traceFunctionCall来进行定位,traceCode我们都比较熟悉,但是在这个样本里面不是很好用,因为粒度太细了要trace很久,感兴趣的可以试试看,也可以只trace一会然后停下来,然后聚焦bangcle_internal_crypto这个函数内部的一个控制流走向,因为我们前面就是跟到这里跟不下去了
然后我们还可以使用Unidbg封装好的一个traceFunctionCall,粒度稍微粗糙一些但是够用了,这里就不多介绍了,因为我们的明文分组是刚好19个,根据标准的填充还会再填充一个分组,所以应该是20,但是这个traceFunctionCall还是有点问题的,有的时候trace不全,即次数会出现遗漏,这里仅提供一个思路~
最后一个0x30ec就是我们刚刚字符串定位到的函数了
接下来我们先来简单介绍一下白盒SM4的DFA差分故障攻击,详细的数学原理感兴趣的可以参考:浅析SM4中的DFA attack-安全KER - 安全资讯平台,这里就不多赘述了
工具准备:SideChannelMarvels/JeanGrey: Tools to perform differential fault analysis attacks (DFA).
SideChannelMarvels/Stark: Repository of small utilities related to key recovery
我们可以先来看一份SM4的DFA攻击代码(参考:guojuntang/sm4_dfa: differential fault analysis attacks (DFA) against SM4)然后来总结一下注入故障的位置与时机
涉及的数学原理其实是比较复杂的,这里我就直接总结一下:
注入攻击的轮次时机:29-30-31-32,分别拿到对应的轮密钥
注入攻击的故障要求:第29轮>13个字节的差分(基本16个字节的差分),第30轮129个字节的差分,第32轮5个字节的差分,这些是质量最高的差分范围
当然这些也只是理论,实战的时候你会发现其实会有些变化
简单介绍完方案以后我们来开始注入攻击吧,从最后一组分组的最后一轮开始,这里输出了前后的value确保注入故障成功
正确的结果是3764c30d86577eab5ad61cc1cc7355f7,注入故障以后是47d601cf86577eab5ad61cc1cc7355f7,观察了一下故障字节是四个字节,不符合差分要求,那就先继续往上一轮注入看看,只需要修改一下偏移,我选择的是0x3764,故障密文是74f4709ae76f27ca5ad61cc1cc7355f7,故障字节8个字节,符合要求,在这个位置继续注入一次,每轮拿到两个故障密文,新的故障密文是b3801e6bdc3a139c5ad61cc1cc7355f7,也是8个字节的故障符合要求
然后继续往第30轮注入,我选择的是0x3734,故障密文分别是2a4da31a9398bd3977fb7b8bcc7355f7、f707f9ef53227db06aea10f1cc7355f7,故障密文都是12个字节,符合要求
继续往第29轮注入,我选的是0x3704,故障密文分别是e1320d54029a01d0c67d533720cceaa4、6ff24e4cc64870f0f1ac2ba4011bf052,16个字节的故障,符合要求
然后我们可以先放到phoenixSM4看看
tracefile里面的内容如下
结果如下
还差了第29轮的轮密钥,那我们就继续往上一轮注入攻击吧,我选的是0x36D4,故障密文分别是9d2fe59c814b4115072182f8279b69a6、c12dc7f7e8527e8713d8f637b979447d,基本都是16个字节的差分,然后继续phoenixSM4看看,结果出来了
至此我们拿到轮密钥了,接下来就是通过轮密钥还原主密钥,这里使用的是SM4_Keyschedule这个前面贴出的优秀工具
密钥就是39B8EC81 9A4A5585 40AFD76E 142A2B9E,IV就是62636461313233666364346432303139,放到CyberChef里面解密会发现报错:Invalid PKCS#7 padding.
看起来像是填充出现了问题,难道是魔改了填充吗?我当时的分析思路是:
1、是否魔改了填充,然后去看了一下最后一组的明文内容,发现填充没有问题
2、密文是否做了别的操作,观察了一下代码发现没有
3、是否是密文端序的问题,转换了一下端序继续使用SM4_Keyschedule发现轮密钥出不来,看起来不是密文端序的问题了
4、是否是标准的Base64,因为我一开始是使用抓包的结果来解密的,看了一下发现是标准的
5、白盒SM4的DFA是否受IV的影响,理论上是不受影响的,并且白盒AES的DFA也是不受IV影响的,这里我将最后一组明文内容改成了chuxin,并且手动补齐了填充,这样当作ECB的模式来重新DFA发现轮密钥还是一样的,也从实践证明了确实不受IV的影响
6、是否是轮密钥端序的问题,比如我们前面的是EDF3A9FA 682E0F96 B2D12B44 21E6B235,那有没有可能是FAA9F3ED 960F2E68 442BD1B2 35B2E621?试试看
看到这个Key,稳啦,这里就是轮密钥端序的问题,这里是SM4_Keyschedule和phoenixSM4的端序不一致导致的问题,感兴趣的可以修改一下源码方便以后的使用~
function main() {
Java.perform(function () {
var ByteString = Java.use("com.android.okhttp.okio.ByteString");
function toBase64(data) {
return ByteString.of(data).base64();
}
function toHex(data) {
return ByteString.of(data).hex();
}
let CryptoTool = Java.use("com.bangcle.CryptoTool");
CryptoTool["qsm4EncryptByteArr"].implementation = function (bArr, str, bArr2) {
console.log(`CryptoTool.qsm4EncryptByteArr is called: bArr=${toHex(bArr)}, str=${str}, bArr2=${toHex(bArr2)}`);
let result = this["qsm4EncryptByteArr"](bArr, str, bArr2);
console.log(`CryptoTool.qsm4EncryptByteArr result=${toBase64(result)}`);
return result;
};
})
}
function main() {
Java.perform(function () {
var ByteString = Java.use("com.android.okhttp.okio.ByteString");
function toBase64(data) {
return ByteString.of(data).base64();
}
function toHex(data) {
return ByteString.of(data).hex();
}
let CryptoTool = Java.use("com.bangcle.CryptoTool");
CryptoTool["qsm4EncryptByteArr"].implementation = function (bArr, str, bArr2) {
console.log(`CryptoTool.qsm4EncryptByteArr is called: bArr=${toHex(bArr)}, str=${str}, bArr2=${toHex(bArr2)}`);
let result = this["qsm4EncryptByteArr"](bArr, str, bArr2);
console.log(`CryptoTool.qsm4EncryptByteArr result=${toBase64(result)}`);
return result;
};
})
}
public static byte[] hexStringToBytes(String hexString) {
if (hexString.isEmpty()) {
return null;
}
hexString = hexString.replace(" ","");
hexString = hexString.toLowerCase();
final byte[] byteArray = new byte[hexString.length() >> 1];
int index = 0;
for (int i = 0; i < hexString.length(); i++) {
if (index > hexString.length() - 1) {
return byteArray;
}
byte highDit = (byte) (Character.digit(hexString.charAt(index), 16)
& 0xFF);
byte lowDit = (byte) (Character.digit(hexString.charAt(index + 1),
16) & 0xFF);
byteArray[i] = (byte) (highDit << 4 | lowDit);
index += 2;
}
return byteArray;
}
public static String bytesTohexString(byte[] bytes) {
StringBuffer sb = new StringBuffer();
for(int i = 0; i < bytes.length; i++) {
String hex = Integer.toHexString(bytes[i] & 0xFF);
if(hex.length() < 2){
sb.append(0);
}
sb.append(hex);
}
return sb.toString();
}
public static String readFile(String filePath) {
StringBuilder content = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
String line;
while ((line = reader.readLine()) != null) {
content.append(line).append("\n");
}
} catch (IOException e) {
e.printStackTrace();
}
return content.toString();
}
public void call(){
byte[] arg1 = hexStringToBytes("这里就不给出完整明文了");
String arg2 = readFile("unidbg-android/src/test/java/com/tengshi/table");
byte[] arg3 = hexStringToBytes("62636461313233666364346432303139");
DvmObject<?> qsm4EncryptByteArr = NativeApi.callStaticJniMethodObject(emulator, "qsm4EncryptByteArr", arg1, arg2, arg3);
byte[] bytes = (byte[]) qsm4EncryptByteArr.getValue();
System.out.println("result => " + new String(Base64.getEncoder().encode(bytes)));
System.out.println("result => " + bytesTohexString(bytes));
}
public static byte[] hexStringToBytes(String hexString) {
if (hexString.isEmpty()) {
return null;
}
hexString = hexString.replace(" ","");
hexString = hexString.toLowerCase();
final byte[] byteArray = new byte[hexString.length() >> 1];
int index = 0;
for (int i = 0; i < hexString.length(); i++) {
if (index > hexString.length() - 1) {
return byteArray;
}
byte highDit = (byte) (Character.digit(hexString.charAt(index), 16)
& 0xFF);
byte lowDit = (byte) (Character.digit(hexString.charAt(index + 1),
16) & 0xFF);
byteArray[i] = (byte) (highDit << 4 | lowDit);
index += 2;
}
return byteArray;
}
public static String bytesTohexString(byte[] bytes) {
StringBuffer sb = new StringBuffer();
for(int i = 0; i < bytes.length; i++) {
String hex = Integer.toHexString(bytes[i] & 0xFF);
if(hex.length() < 2){
sb.append(0);
}
sb.append(hex);
}
return sb.toString();
}
public static String readFile(String filePath) {
StringBuilder content = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
String line;
while ((line = reader.readLine()) != null) {
content.append(line).append("\n");
}
} catch (IOException e) {
e.printStackTrace();
}
return content.toString();
}
public void call(){
byte[] arg1 = hexStringToBytes("这里就不给出完整明文了");
String arg2 = readFile("unidbg-android/src/test/java/com/tengshi/table");
byte[] arg3 = hexStringToBytes("62636461313233666364346432303139");
DvmObject<?> qsm4EncryptByteArr = NativeApi.callStaticJniMethodObject(emulator, "qsm4EncryptByteArr", arg1, arg2, arg3);
byte[] bytes = (byte[]) qsm4EncryptByteArr.getValue();
System.out.println("result => " + new String(Base64.getEncoder().encode(bytes)));
System.out.println("result => " + bytesTohexString(bytes));
}
if (pathname.equals("/proc/self/maps")){
return FileResult.success(new SimpleFileIO(oflags, new File("unidbg-android/src/test/resources/Test/tengshi_maps") , pathname));
}
if (pathname.equals("/proc/self/maps")){
return FileResult.success(new SimpleFileIO(oflags, new File("unidbg-android/src/test/resources/Test/tengshi_maps") , pathname));
}
[main]D/crypto_tool: bangcle crypto tool error code : -1
Exception in thread "main" java.lang.NullPointerException
at com.tengshi.encrypt.call(encrypt.java:248)
at com.tengshi.encrypt.main(encrypt.java:273)
[main]D/crypto_tool: bangcle crypto tool error code : -1
Exception in thread "main" java.lang.NullPointerException
at com.tengshi.encrypt.call(encrypt.java:248)
at com.tengshi.encrypt.main(encrypt.java:273)
jbyteArray __fastcall Java_com_bangcle_CryptoTool_qsm4EncryptByteArr(
JNIEnv *a1,
__int64 a2,
void *a3,
__int64 a4,
__int64 a5)
{
int v5;
JNIEnv *v10;
unsigned int v11;
int v12;
unsigned int v13;
jbyte *v14;
char *v15;
jbyteArray v16;
v10 = a1;
v14 = 0LL;
v15 = 0LL;
dword_18018 = 9;
v12 = sub_5674(a3, a4);
if ( v12 )
{
v12 = -1;
}
else
{
v14 = (*v10)->GetByteArrayElements(v10, a3, 0LL);
if ( v14 )
{
v13 = (*v10)->GetArrayLength(v10, a3);
v11 = 16 * (v13 / 16 + 1);
v15 = _cxa_finalize(v11);
if ( v15 )
{
v12 = sub_509C(&v10, v14, v13, v15, &v11, a4, a5);
if ( !v12 )
{
v16 = (*v10)->NewByteArray(v10, v11);
(*v10)->SetByteArrayRegion(v10, v16, 0LL, v11, v15);
}
}
else
{
v12 = -1;
}
}
else
{
v12 = -1;
}
}
if ( v14 )
(*v10)->ReleaseByteArrayElements(v10, a3, v14, 2LL);
if ( v15 )
strchr(v15, v5);
if ( !v12 )
return v16;
strtoul((&dword_0 + 3), "crypto_tool", "bangcle crypto tool error code : %d");
return 0LL;
}
jbyteArray __fastcall Java_com_bangcle_CryptoTool_qsm4EncryptByteArr(
JNIEnv *a1,
__int64 a2,
void *a3,
__int64 a4,
__int64 a5)
{
int v5;
JNIEnv *v10;
unsigned int v11;
int v12;
unsigned int v13;
jbyte *v14;
char *v15;
jbyteArray v16;
v10 = a1;
v14 = 0LL;
v15 = 0LL;
dword_18018 = 9;
v12 = sub_5674(a3, a4);
if ( v12 )
{
v12 = -1;
}
else
{
v14 = (*v10)->GetByteArrayElements(v10, a3, 0LL);
if ( v14 )
{
v13 = (*v10)->GetArrayLength(v10, a3);
v11 = 16 * (v13 / 16 + 1);
v15 = _cxa_finalize(v11);
if ( v15 )
{
v12 = sub_509C(&v10, v14, v13, v15, &v11, a4, a5);
if ( !v12 )
{
v16 = (*v10)->NewByteArray(v10, v11);
(*v10)->SetByteArrayRegion(v10, v16, 0LL, v11, v15);
}
}
else
{
v12 = -1;
}
}
else
{
v12 = -1;
}
}
if ( v14 )
(*v10)->ReleaseByteArrayElements(v10, a3, v14, 2LL);
if ( v15 )
strchr(v15, v5);
if ( !v12 )
return v16;
strtoul((&dword_0 + 3), "crypto_tool", "bangcle crypto tool error code : %d");
return 0LL;
}
__int64 __fastcall sub_509C(JNIEnv *a1, __int64 a2, unsigned int a3, __int64 a4, __int64 a5, __int64 a6, __int64 a7)
{
int v7;
unsigned int v16;
signed int v17;
unsigned int v18;
unsigned int v19;
__int64 v20;
__int64 v21;
char *v22;
v20 = 0LL;
v21 = 0LL;
v22 = 0LL;
v16 = 0;
bangcle_init(*a1);
v17 = (*((*a1)->reserved0 + 168))(*a1, a6);
if ( (v17 & 1) != 0 )
{
v16 = -1;
}
else
{
v21 = (*((*a1)->reserved0 + 169))(*a1, a6, 0LL);
if ( v21 )
{
v18 = v17 / 2;
v22 = _cxa_finalize((v17 / 2));
if ( v22 )
{
sub_4F9C(v21, v17, v22);
if ( !a7 )
{
if ( dword_18018 == 9 )
v16 = bangcle_QSM4_ecb_encrypt(a2, a3, a4, a5, v22, v18, 1LL);
else
v16 = -1;
}
if ( a7 )
{
v20 = (*((*a1)->reserved0 + 184))(*a1, a7, 0LL);
if ( v20 )
{
v19 = (*((*a1)->reserved0 + 171))(*a1, a7);
if ( dword_18018 == 8 )
bangcle_skb_encrypt(a2, a3, a4, a5, v20, v19, v22, v18, 1, 1);
if ( dword_18018 == 9 )
v16 = bangcle_QSM4_cbc_encrypt(a2, a3, a4, a5, v20, v19, v22, v18, 1);
else
v16 = -1;
}
else
{
v16 = -1;
}
}
}
else
{
v16 = -1;
}
}
else
{
v16 = -1;
}
}
if ( v21 )
(*((*a1)->reserved0 + 170))(*a1, a6, v21);
if ( v22 )
strchr(v22, v7);
if ( v20 )
(*((*a1)->reserved0 + 192))(*a1, a7, v20, 2LL);
return v16;
}
__int64 __fastcall sub_509C(JNIEnv *a1, __int64 a2, unsigned int a3, __int64 a4, __int64 a5, __int64 a6, __int64 a7)
{
int v7;
unsigned int v16;
signed int v17;
unsigned int v18;
unsigned int v19;
__int64 v20;
__int64 v21;
char *v22;
v20 = 0LL;
v21 = 0LL;
v22 = 0LL;
v16 = 0;
bangcle_init(*a1);
v17 = (*((*a1)->reserved0 + 168))(*a1, a6);
if ( (v17 & 1) != 0 )
{
v16 = -1;
}
else
{
v21 = (*((*a1)->reserved0 + 169))(*a1, a6, 0LL);
if ( v21 )
{
v18 = v17 / 2;
v22 = _cxa_finalize((v17 / 2));
if ( v22 )
{
sub_4F9C(v21, v17, v22);
if ( !a7 )
{
if ( dword_18018 == 9 )
v16 = bangcle_QSM4_ecb_encrypt(a2, a3, a4, a5, v22, v18, 1LL);
else
v16 = -1;
}
if ( a7 )
{
v20 = (*((*a1)->reserved0 + 184))(*a1, a7, 0LL);
if ( v20 )
{
v19 = (*((*a1)->reserved0 + 171))(*a1, a7);
if ( dword_18018 == 8 )
bangcle_skb_encrypt(a2, a3, a4, a5, v20, v19, v22, v18, 1, 1);
if ( dword_18018 == 9 )
v16 = bangcle_QSM4_cbc_encrypt(a2, a3, a4, a5, v20, v19, v22, v18, 1);
else
v16 = -1;
}
else
{
v16 = -1;
}
}
}
else
{
v16 = -1;
}
}
else
{
v16 = -1;
}
}
if ( v21 )
(*((*a1)->reserved0 + 170))(*a1, a6, v21);
if ( v22 )
strchr(v22, v7);
if ( v20 )
(*((*a1)->reserved0 + 192))(*a1, a7, v20, 2LL);
return v16;
}
emulator.attach().addBreakPoint(module.base + 0x5100, new BreakPointCallback() {
@Override
public boolean onHit(Emulator<?> emulator, long address) {
emulator.getBackend().reg_write(Arm64Const.UC_ARM64_REG_X0,0x40008);
return true;
}
});
emulator.attach().addBreakPoint(module.base + 0x5100, new BreakPointCallback() {
@Override
public boolean onHit(Emulator<?> emulator, long address) {
emulator.getBackend().reg_write(Arm64Const.UC_ARM64_REG_X0,0x40008);
return true;
}
});
__int64 __fastcall bangcle_internal_crypto(
__int64 a1,
int a2,
__int64 a3,
__int64 a4,
__int64 a5,
unsigned int a6,
__int64 a7,
unsigned int a8,
__int64 a9)
{
unsigned int prio;
int v17;
int v18;
__int64 v19;
int v20;
int v21;
v19 = 0LL;
v17 = 0;
if ( dword_18008 )
{
if ( dword_1800C )
{
if ( sub_1704(a7, a8, &v19) == -1 )
{
prio = 5;
}
else
{
if ( !v20 || v20 == 3 || v20 == 4 || v20 == 7 || v20 == 9 )
{
v17 = 16;
}
else if ( v20 == 1 || v20 == 2 || v20 == 5 || v20 == 6 )
{
v17 = 8;
}
v18 = sub_2084(a1, a3, a5, a6, v17, a7);
if ( v18 <= 0 )
{
if ( sub_1EDC(a9, &v19) )
{
prio = 2;
}
else if ( *(a9 + 28) || !(a2 % v17) )
{
if ( v21 == 1 && a2 % v17 )
prio = 14;
else
prio = 3;
}
else
{
prio = 14;
}
}
else
{
prio = v18;
}
}
}
else
{
prio = 7;
}
}
else
{
prio = 6;
}
sub_1D2C(&v19);
return prio;
}
__int64 __fastcall bangcle_internal_crypto(
__int64 a1,
int a2,
__int64 a3,
__int64 a4,
__int64 a5,
unsigned int a6,
__int64 a7,
unsigned int a8,
__int64 a9)
{
unsigned int prio;
int v17;
int v18;
__int64 v19;
int v20;
int v21;
v19 = 0LL;
v17 = 0;
if ( dword_18008 )
{
if ( dword_1800C )
{
if ( sub_1704(a7, a8, &v19) == -1 )
{
prio = 5;
}
else
{
if ( !v20 || v20 == 3 || v20 == 4 || v20 == 7 || v20 == 9 )
{
v17 = 16;
}
else if ( v20 == 1 || v20 == 2 || v20 == 5 || v20 == 6 )
{
v17 = 8;
}
v18 = sub_2084(a1, a3, a5, a6, v17, a7);
if ( v18 <= 0 )
{
if ( sub_1EDC(a9, &v19) )
{
prio = 2;
}
else if ( *(a9 + 28) || !(a2 % v17) )
{
if ( v21 == 1 && a2 % v17 )
prio = 14;
else
prio = 3;
}
else
{
prio = 14;
}
}
else
{
prio = v18;
}
}
}
else
{
prio = 7;
}
}
else
{
prio = 6;
}
sub_1D2C(&v19);
return prio;
}
__int64 __fastcall bangcle_WB_QSM4_encrypt(__int64 a1, __int64 a2, __int64 *a3)
{
int i;
int j;
int v7;
int v8;
int v9;
int v10;
int v11;
int v12;
int v13;
int v14;
unsigned int v15;
int v16;
int v17;
int v18;
int v19;
int v20;
int v21;
int v22;
int v23;
unsigned int v24;
int v25;
unsigned int v26;
unsigned int v27;
unsigned int v28;
unsigned int v29;
unsigned int v30;
unsigned int v31;
unsigned int v32;
unsigned int v33;
unsigned int v34;
unsigned int v35;
unsigned int v36;
unsigned int v37;
unsigned int v38;
unsigned int v39;
unsigned int v40;
unsigned int v41;
unsigned int v42;
__int64 v43;
_BYTE v44[16];
v43 = *a3;
for ( i = 0; i <= 15; ++i )
v44[i] = *(bangcle_QSM4_encrypt_xor0 + *(a1 + i));
v7 = sub_2DA4(v44, 0LL);
v16 = sub_2DA4(v44, 1LL);
v25 = sub_2DA4(v44, 2LL);
v34 = sub_2DA4(v44, 3LL);
v8 = v7 ^ sub_2EA8(v16 ^ v25 ^ v34, 0LL, v43);
v17 = v16 ^ sub_2EA8(v8 ^ v25 ^ v34, 1LL, v43);
v26 = v25 ^ sub_2EA8(v8 ^ v17 ^ v34, 2LL, v43);
v35 = v34 ^ sub_2EA8(v8 ^ v17 ^ v26, 3LL, v43);
v9 = v8 ^ sub_2EA8(v17 ^ v26 ^ v35, 4LL, v43);
v18 = v17 ^ sub_2EA8(v9 ^ v26 ^ v35, 5LL, v43);
v27 = v26 ^ sub_2EA8(v9 ^ v18 ^ v35, 6LL, v43);
v36 = v35 ^ sub_2EA8(v9 ^ v18 ^ v27, 7LL, v43);
v10 = v9 ^ sub_2EA8(v18 ^ v27 ^ v36, 8LL, v43);
v19 = v18 ^ sub_2EA8(v10 ^ v27 ^ v36, 9LL, v43);
v28 = v27 ^ sub_2EA8(v10 ^ v19 ^ v36, 10LL, v43);
v37 = v36 ^ sub_2EA8(v10 ^ v19 ^ v28, 11LL, v43);
v11 = v10 ^ sub_2EA8(v19 ^ v28 ^ v37, 12LL, v43);
v20 = v19 ^ sub_2EA8(v11 ^ v28 ^ v37, 13LL, v43);
v29 = v28 ^ sub_2EA8(v11 ^ v20 ^ v37, 14LL, v43);
v38 = v37 ^ sub_2EA8(v11 ^ v20 ^ v29, 15LL, v43);
v12 = v11 ^ sub_2EA8(v20 ^ v29 ^ v38, 16LL, v43);
v21 = v20 ^ sub_2EA8(v12 ^ v29 ^ v38, 17LL, v43);
v30 = v29 ^ sub_2EA8(v12 ^ v21 ^ v38, 18LL, v43);
v39 = v38 ^ sub_2EA8(v12 ^ v21 ^ v30, 19LL, v43);
v13 = v12 ^ sub_2EA8(v21 ^ v30 ^ v39, 20LL, v43);
v22 = v21 ^ sub_2EA8(v13 ^ v30 ^ v39, 21LL, v43);
v31 = v30 ^ sub_2EA8(v13 ^ v22 ^ v39, 22LL, v43);
v40 = v39 ^ sub_2EA8(v13 ^ v22 ^ v31, 23LL, v43);
v14 = v13 ^ sub_2EA8(v22 ^ v31 ^ v40, 24LL, v43);
v23 = v22 ^ sub_2EA8(v14 ^ v31 ^ v40, 25LL, v43);
v32 = v31 ^ sub_2EA8(v14 ^ v23 ^ v40, 26LL, v43);
v41 = v40 ^ sub_2EA8(v14 ^ v23 ^ v32, 27LL, v43);
v15 = v14 ^ sub_2EA8(v23 ^ v32 ^ v41, 28LL, v43);
v24 = v23 ^ sub_2EA8(v15 ^ v32 ^ v41, 29LL, v43);
v33 = v32 ^ sub_2EA8(v15 ^ v24 ^ v41, 30LL, v43);
v42 = v41 ^ sub_2EA8(v15 ^ v24 ^ v33, 31LL, v43);
sub_2E3C(v42, a2);
sub_2E3C(v33, a2 + 4);
sub_2E3C(v24, a2 + 8);
sub_2E3C(v15, a2 + 12);
for ( j = 0; j <= 15; ++j )
*(a2 + j) = *(bangcle_QSM4_encrypt_xor1 + *(a2 + j));
return __stack_chk_guard;
}
__int64 __fastcall bangcle_WB_QSM4_encrypt(__int64 a1, __int64 a2, __int64 *a3)
{
int i;
int j;
int v7;
int v8;
int v9;
int v10;
int v11;
int v12;
int v13;
int v14;
unsigned int v15;
int v16;
int v17;
int v18;
int v19;
int v20;
int v21;
int v22;
int v23;
unsigned int v24;
int v25;
unsigned int v26;
unsigned int v27;
unsigned int v28;
unsigned int v29;
unsigned int v30;
unsigned int v31;
unsigned int v32;
unsigned int v33;
unsigned int v34;
unsigned int v35;
unsigned int v36;
unsigned int v37;
unsigned int v38;
unsigned int v39;
unsigned int v40;
unsigned int v41;
unsigned int v42;
__int64 v43;
_BYTE v44[16];
v43 = *a3;
for ( i = 0; i <= 15; ++i )
v44[i] = *(bangcle_QSM4_encrypt_xor0 + *(a1 + i));
v7 = sub_2DA4(v44, 0LL);
v16 = sub_2DA4(v44, 1LL);
v25 = sub_2DA4(v44, 2LL);
v34 = sub_2DA4(v44, 3LL);
v8 = v7 ^ sub_2EA8(v16 ^ v25 ^ v34, 0LL, v43);
v17 = v16 ^ sub_2EA8(v8 ^ v25 ^ v34, 1LL, v43);
v26 = v25 ^ sub_2EA8(v8 ^ v17 ^ v34, 2LL, v43);
v35 = v34 ^ sub_2EA8(v8 ^ v17 ^ v26, 3LL, v43);
v9 = v8 ^ sub_2EA8(v17 ^ v26 ^ v35, 4LL, v43);
v18 = v17 ^ sub_2EA8(v9 ^ v26 ^ v35, 5LL, v43);
v27 = v26 ^ sub_2EA8(v9 ^ v18 ^ v35, 6LL, v43);
v36 = v35 ^ sub_2EA8(v9 ^ v18 ^ v27, 7LL, v43);
v10 = v9 ^ sub_2EA8(v18 ^ v27 ^ v36, 8LL, v43);
v19 = v18 ^ sub_2EA8(v10 ^ v27 ^ v36, 9LL, v43);
v28 = v27 ^ sub_2EA8(v10 ^ v19 ^ v36, 10LL, v43);
v37 = v36 ^ sub_2EA8(v10 ^ v19 ^ v28, 11LL, v43);
v11 = v10 ^ sub_2EA8(v19 ^ v28 ^ v37, 12LL, v43);
v20 = v19 ^ sub_2EA8(v11 ^ v28 ^ v37, 13LL, v43);
v29 = v28 ^ sub_2EA8(v11 ^ v20 ^ v37, 14LL, v43);
v38 = v37 ^ sub_2EA8(v11 ^ v20 ^ v29, 15LL, v43);
v12 = v11 ^ sub_2EA8(v20 ^ v29 ^ v38, 16LL, v43);
v21 = v20 ^ sub_2EA8(v12 ^ v29 ^ v38, 17LL, v43);
v30 = v29 ^ sub_2EA8(v12 ^ v21 ^ v38, 18LL, v43);
v39 = v38 ^ sub_2EA8(v12 ^ v21 ^ v30, 19LL, v43);
v13 = v12 ^ sub_2EA8(v21 ^ v30 ^ v39, 20LL, v43);
v22 = v21 ^ sub_2EA8(v13 ^ v30 ^ v39, 21LL, v43);
v31 = v30 ^ sub_2EA8(v13 ^ v22 ^ v39, 22LL, v43);
v40 = v39 ^ sub_2EA8(v13 ^ v22 ^ v31, 23LL, v43);
v14 = v13 ^ sub_2EA8(v22 ^ v31 ^ v40, 24LL, v43);
v23 = v22 ^ sub_2EA8(v14 ^ v31 ^ v40, 25LL, v43);
v32 = v31 ^ sub_2EA8(v14 ^ v23 ^ v40, 26LL, v43);
v41 = v40 ^ sub_2EA8(v14 ^ v23 ^ v32, 27LL, v43);
v15 = v14 ^ sub_2EA8(v23 ^ v32 ^ v41, 28LL, v43);
v24 = v23 ^ sub_2EA8(v15 ^ v32 ^ v41, 29LL, v43);
v33 = v32 ^ sub_2EA8(v15 ^ v24 ^ v41, 30LL, v43);
v42 = v41 ^ sub_2EA8(v15 ^ v24 ^ v33, 31LL, v43);
sub_2E3C(v42, a2);
sub_2E3C(v33, a2 + 4);
sub_2E3C(v24, a2 + 8);
sub_2E3C(v15, a2 + 12);
for ( j = 0; j <= 15; ++j )
*(a2 + j) = *(bangcle_QSM4_encrypt_xor1 + *(a2 + j));
return __stack_chk_guard;
}
[!]
[*] RX@0x1200502c[libbangcle_crypto_tool.so]0x502c CALL -> 0x1020 (Count: 20)
[!]
[*] RX@0x120030bc[libbangcle_crypto_tool.so]0x30bc CALL -> 0x2da4 (Count: 20)
[!]
[*] RX@0x12003568[libbangcle_crypto_tool.so]0x3568 CALL -> 0x2ea8 (Count: 20)
[!]
[*] RX@0x120037f4[libbangcle_crypto_tool.so]0x37f4 CALL -> 0x2e3c (Count: 20)
[!]
[*] RX@0x12002c2c[libbangcle_crypto_tool.so]0x2c2c CALL -> 0x30ec (Count: 20)
[!]
[*] RX@0x1200502c[libbangcle_crypto_tool.so]0x502c CALL -> 0x1020 (Count: 20)
[!]
[*] RX@0x120030bc[libbangcle_crypto_tool.so]0x30bc CALL -> 0x2da4 (Count: 20)
[!]
[*] RX@0x12003568[libbangcle_crypto_tool.so]0x3568 CALL -> 0x2ea8 (Count: 20)
[!]
[*] RX@0x120037f4[libbangcle_crypto_tool.so]0x37f4 CALL -> 0x2e3c (Count: 20)
[!]
[*] RX@0x12002c2c[libbangcle_crypto_tool.so]0x2c2c CALL -> 0x30ec (Count: 20)
import random
from enum import Enum
FaultStatus = Enum('FaultStatus',
'Crash Loop NoFault MinorFault MajorFault WrongFault round31Fault round30Fault round29Fault')
blockSize = 16
sliceSize = blockSize // 4
xor = lambda a, b: list(map(lambda x, y: x ^ y, a, b))
rotl = lambda x, n: ((x << n) & 0xffffffff) | ((x >> (32 - n)) & 0xffffffff)
get_uint32_be = lambda key_data: ((key_data[0] << 24) | (key_data[1] << 16) | (key_data[2] << 8) | (key_data[3]))
get_uint32_le = lambda key_data: ((key_data[3] << 24) | (key_data[2] << 16) | (key_data[1] << 8) | (key_data[0]))
put_uint32_be = lambda n: [((n >> 24) & 0xff), ((n >> 16) & 0xff), ((n >> 8) & 0xff), ((n) & 0xff)]
bytes_to_list = lambda data: [i for i in data]
list_to_bytes = lambda data: b''.join([bytes((i,)) for i in data])
dump_byte = lambda a: print(''.join(map(lambda x: ('/x' if len(hex(x)) >= 4 else '/x0') + hex(x)[2:], a)))
l_inv = lambda c: c ^ rotl(c, 2) ^ rotl(c, 4) ^ rotl(c, 8) ^ rotl(c, 12) ^ rotl(c, 14) ^ rotl(c, 16) ^ rotl(c,
18) ^ rotl(
c, 22) ^ rotl(c, 24) ^ rotl(c, 30)
int2bytes = lambda state, size: (state).to_bytes(size, byteorder='big', signed=False)
bytes2int = lambda state: int.from_bytes(state, 'big', signed=False)
intersect = lambda a, b: [val for val in a if val in b]
singleState = lambda a, index: (a >> (index * 8)) & 0xff
getSlices = lambda block: [(block >> (32 * i) & 0xffffffff) for i in range(0, 4)]
byte2slices = lambda state: [get_uint32_be(state[i * 4: (i + 1) * 4]) for i in range(4)]
find_candidate_index = lambda diff: [i for i in range(4, len(diff)) if diff[i] != b'\x00'][0] % 4
def check_diff(diffmap, n):
for i in range(n - 1):
if diffmap[i] is not i:
return False
return True
SM4_ENCRYPT = 0
SM4_DECRYPT = 1
SM4_BOXES_TABLE = [
0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c,
0x05, 0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86,
0x06, 0x99, 0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed,
0xcf, 0xac, 0x62, 0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa,
0x75, 0x8f, 0x3f, 0xa6, 0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c,
0x19, 0xe6, 0x85, 0x4f, 0xa8, 0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb,
0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35, 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25,
0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87, 0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52,
0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e, 0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38,
0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1, 0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34,
0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3, 0x1d, 0xf6, 0xe2, 0x2e, 0x82,
0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f, 0xd5, 0xdb, 0x37, 0x45,
0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51, 0x8d, 0x1b, 0xaf,
0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8, 0x0a, 0xc1,
0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0, 0x89,
0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,
0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39,
0x48,
]
SM4_FK = [0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc]
SM4_CK = [
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
]
def gen_IN_table():
IN_table = [[[] for i in range(2 ** 8)] for j in range(2 ** 8)]
for diff_in in range(1, 2 ** 8):
for x in range(2 ** 8):
diff_out = SM4_BOXES_TABLE[x] ^ SM4_BOXES_TABLE[diff_in ^ x]
IN_table[diff_in][diff_out].append(x)
return IN_table
def recovery_key(last_round_key):
rk = [0] * 36
rk[32:] = last_round_key[::-1]
for i in range(31, -1, -1):
rk[i] = rk[i + 4] ^ round_key(rk[i + 1] ^ rk[i + 2] ^ rk[i + 3] ^ SM4_CK[i])
rk[:4] = xor(rk[:4], SM4_FK)
return rk
def get_masterKey(sk):
MK = b''.join(int2bytes(x, sliceSize) for x in sk[:4])
return MK
def round_key(ka):
b = [0, 0, 0, 0]
a = put_uint32_be(ka)
b[0] = SM4_BOXES_TABLE[a[0]]
b[1] = SM4_BOXES_TABLE[a[1]]
b[2] = SM4_BOXES_TABLE[a[2]]
b[3] = SM4_BOXES_TABLE[a[3]]
bb = get_uint32_be(b[0:4])
rk = bb ^ (rotl(bb, 13)) ^ (rotl(bb, 23))
return rk
def set_key(key, mode):
key = bytes_to_list(key)
sk = [0] * 32
MK = [0, 0, 0, 0]
k = [0] * 36
MK[0:4] = byte2slices(key)
k[0:4] = xor(MK[0:4], SM4_FK[0:4])
for i in range(32):
k[i + 4] = k[i] ^ (
round_key(k[i + 1] ^ k[i + 2] ^ k[i + 3] ^ SM4_CK[i]))
sk[i] = k[i + 4]
mode = mode
if mode == SM4_DECRYPT:
for idx in range(16):
t = sk[idx]
sk[idx] = sk[31 - idx]
sk[31 - idx] = t
return sk
def f_function(x0, x1, x2, x3, rk):
def sm4_l_t(ka):
b = [0, 0, 0, 0]
a = put_uint32_be(ka)
b[0] = SM4_BOXES_TABLE[a[0]]
b[1] = SM4_BOXES_TABLE[a[1]]
b[2] = SM4_BOXES_TABLE[a[2]]
b[3] = SM4_BOXES_TABLE[a[3]]
bb = get_uint32_be(b[0:4])
c = bb ^ (rotl(bb, 2)) ^ (rotl(bb, 10)) ^ (rotl(bb, 18)) ^ (rotl(bb, 24))
return c
return (x0 ^ sm4_l_t(x1 ^ x2 ^ x3 ^ rk))
def round(sk, in_put):
out_put = []
ulbuf = [0] * 36
ulbuf[0:4] = byte2slices(in_put)
for idx in range(32):
ulbuf[idx + 4] = f_function(ulbuf[idx], ulbuf[idx + 1], ulbuf[idx + 2], ulbuf[idx + 3], sk[idx])
out_put += put_uint32_be(ulbuf[35])
out_put += put_uint32_be(ulbuf[34])
out_put += put_uint32_be(ulbuf[33])
out_put += put_uint32_be(ulbuf[32])
return out_put
def sm4_encrypt(in_put, sk):
in_put = bytes_to_list(in_put)
output = round(sk, in_put)
return list_to_bytes(output)
def gen_fault_cipher(in_put, sk, inject_round, verbose=1):
in_put = bytes_to_list(in_put)
out_put = []
ulbuf = [0] * 36
ulbuf[0:4] = byte2slices(in_put)
for idx in range(32):
if idx is inject_round:
diff = random.randint(1, 2 ** 8 - 1)
offset = random.randrange(0, 25, 8)
index = random.randint(1, 3)
if (verbose > 3):
print("round %d:Inject diff 0x%.2x at offset %d" % (inject_round, diff, offset))
ulbuf[idx + index] ^= diff << offset
ulbuf[idx + 4] = f_function(ulbuf[idx], ulbuf[idx + 1], ulbuf[idx + 2], ulbuf[idx + 3], sk[idx])
out_put += put_uint32_be(ulbuf[35])
out_put += put_uint32_be(ulbuf[34])
out_put += put_uint32_be(ulbuf[33])
out_put += put_uint32_be(ulbuf[32])
return list_to_bytes(out_put)
def decrypt_round(in_put, last_round_key, verbose=1):
output = []
ulbuf = [0] * 36
ulbuf[0:4] = byte2slices(in_put)
round_num = len(last_round_key)
for idx in range(round_num):
ulbuf[idx + 4] = f_function(ulbuf[idx], ulbuf[idx + 1], ulbuf[idx + 2], ulbuf[idx + 3], last_round_key[idx])
if verbose > 3:
print("decrypt round in %d:%x" % (idx, ulbuf[idx + 4]))
output += put_uint32_be(ulbuf[round_num])
output += put_uint32_be(ulbuf[round_num + 1])
output += put_uint32_be(ulbuf[round_num + 2])
output += put_uint32_be(ulbuf[round_num + 3])
return list_to_bytes(output)
def crack_round(roundFaultList, ref, last_round_key=[], verbose=1):
if not last_round_key:
pass
else:
ref = decrypt_round(ref, last_round_key, verbose)
for index in range(len(roundFaultList)):
roundFaultList[index] = decrypt_round(roundFaultList[index], last_round_key, verbose)
return crack_bytes(roundFaultList, ref, verbose)
def check(output, encrypt=None, verbose=1, init=False, _intern={}):
if init:
_intern.clear()
if not _intern:
_intern['goldenref'] = output
if verbose > 2:
print("FI: record golden ref")
return (FaultStatus.NoFault, None)
if output == _intern['goldenref']:
if verbose > 2:
print("FI: no impact")
return (FaultStatus.NoFault, None)
diff = xor(output, _intern['goldenref'])
diffmap = [i for i in range(len(diff)) if diff[i] != 0]
diffsum = len(diffmap)
status = FaultStatus.Loop
if diffsum == 5 or diffsum == 8 or diffsum == 9 or diffsum == 12 or diffsum == 13:
if check_diff(diffmap, diffsum):
if verbose > 2:
if diffsum == 5:
print("FI: good candidate for round31!")
if diffsum == 9 or diffsum == 8:
print("FI: good candidate for round30!")
if diffsum == 13 or diffsum == 12:
print("FI: good candidate for round29!")
if diffsum == 5:
status = FaultStatus.round31Fault
if diffsum == 9 or diffsum == 8:
status = FaultStatus.round30Fault
if diffsum == 12 or diffsum == 13:
status = FaultStatus.round29Fault
return (status, (3 - diffmap[diffsum - 1] % 4))
else:
if verbose > 2:
print("FI: wrong candidate (%2i)" % diffsum)
return (FaultStatus.WrongFault, None)
elif diffsum < 5:
if verbose > 2:
print("FI: too few impact (%2i)" % diffsum)
return (FaultStatus.MinorFault, None)
else:
if verbose > 2:
print("FI: too much impact (%2i)" % diffsum)
return (FaultStatus.MajorFault, None)
def get_candidates(faultCipher, ref, index, verbose=1):
if not hasattr(get_candidates, '_IN_TABLE'):
get_candidates._IN_TABLE = gen_IN_table()
faultCipher = bytes2int(faultCipher)
ref = bytes2int(ref)
ref_slice = getSlices(ref)
fault_slice = getSlices(faultCipher)
delta_C = xor(ref_slice, fault_slice)[3]
delta_B = l_inv(delta_C)
A = ref_slice[0] ^ ref_slice[1] ^ ref_slice[2]
A_star = fault_slice[0] ^ fault_slice[1] ^ fault_slice[2]
alpha = singleState(A ^ A_star, index)
beta = singleState(delta_B, index)
result = get_candidates._IN_TABLE[alpha][beta]
if result:
result = [singleState(A, index) ^ x for x in result]
else:
result = []
print("Error: empty key candidate!")
return result
def crack_bytes(roundFaultList, ref, verbose=1):
candidates = [[], [], [], []]
key = [None] * 4
_, index = check(ref, init=True)
for faultCipher in roundFaultList:
_, index = check(faultCipher)
if index is not None:
if key[index] is not None:
continue
else:
if verbose > 2:
print("bad fault cipher:")
dump_byte(faultCipher)
continue
if verbose > 1:
print("key index at %d" % (index))
c = get_candidates(faultCipher, ref, index, verbose)
if not candidates[index]:
candidates[index] = c
else:
candidates[index] = intersect(candidates[index], c)
if (len(candidates[index]) == 1):
key[index] = candidates[index][0]
if verbose > 1:
print("Round key bytes recovered:")
print(''.join(["%02X" % x if x is not None else ".." for x in key]))
for byte in key:
if (byte is None):
print("Only partly recovered:")
print(''.join(["%02X" % x if x is not None else ".." for x in key]))
return None
return get_uint32_le(key)
def foo():
masterKey = b'\x01\x23\x45\x67\x89\xab\xcd\xef\xfe\xdc\xba\x98\x76\x54\x32\x10'
in_put = b'\x01\x23\x45\x67\x89\xab\xcd\xef\xfe\xdc\xba\x98\x76\x54\x32\x10'
sk = set_key(masterKey, SM4_ENCRYPT)
r31 = [gen_fault_cipher(in_put, sk, 31) for i in range(30)]
r30 = [gen_fault_cipher(in_put, sk, 30) for i in range(30)]
r29 = [gen_fault_cipher(in_put, sk, 29) for i in range(30)]
r28 = [gen_fault_cipher(in_put, sk, 28) for i in range(30)]
ref = sm4_encrypt(in_put, sk)
last_round_key = []
key_schedule = []
last_round_key.append(crack_round(r31, ref))
last_round_key.append(crack_round(r30, ref, last_round_key))
last_round_key.append(crack_round(r29, ref, last_round_key))
last_round_key.append(crack_round(r28, ref, last_round_key))
print(last_round_key)
if __name__ == '__main__':
foo()
import random
from enum import Enum
FaultStatus = Enum('FaultStatus',
'Crash Loop NoFault MinorFault MajorFault WrongFault round31Fault round30Fault round29Fault')
blockSize = 16
sliceSize = blockSize // 4
xor = lambda a, b: list(map(lambda x, y: x ^ y, a, b))
rotl = lambda x, n: ((x << n) & 0xffffffff) | ((x >> (32 - n)) & 0xffffffff)
get_uint32_be = lambda key_data: ((key_data[0] << 24) | (key_data[1] << 16) | (key_data[2] << 8) | (key_data[3]))
get_uint32_le = lambda key_data: ((key_data[3] << 24) | (key_data[2] << 16) | (key_data[1] << 8) | (key_data[0]))
put_uint32_be = lambda n: [((n >> 24) & 0xff), ((n >> 16) & 0xff), ((n >> 8) & 0xff), ((n) & 0xff)]
bytes_to_list = lambda data: [i for i in data]
list_to_bytes = lambda data: b''.join([bytes((i,)) for i in data])
dump_byte = lambda a: print(''.join(map(lambda x: ('/x' if len(hex(x)) >= 4 else '/x0') + hex(x)[2:], a)))
传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!