国密sm4 ECB、CEC模式探究与在iOS中的应用

SM4密码算法是一个分组算法。数据分组长度为128比特,密钥长度为128 比特。加密算法采用32 轮迭代结构,每轮使用一个轮密钥。

我们在iOS中实现可用data字节的形式,即秘钥Data为16位,加密数据Data需为16的整数倍,这两点很重要。

1、ECB模式

观察第一块,和第三块,皆为明文块0,相同的输入产生相同的输出

国密sm4 ECB、CEC模式探究与在iOS中的应用_第1张图片来看下具体代码

sm4Length:原数据的具体长度

unsigned char *plainChar: 原数据

unsigned char *cipherChar = malloc(sm4Length); 加密后的数据

调用: sm4_crypt_ecb(&ctx, SM4_ENCRYPT, sm4Length, plainChar, cipherChar);
具体实现

void sm4_crypt_ecb( sm4_context *ctx,
                   int mode,
                   int length,
                   unsigned char *input,
                   unsigned char *output)
{
    while( length > 0 )
    {
        sm4_one_round( ctx->sk, input, output ); //具体循环单个加密方法,
        input  += 16;
        output += 16;
        length -= 16;
    }

}

可以看出加密形式,单块加密,比较简单有利于计算,误差不会被传送。但是明文也容易被攻击。

此外,对于原文不足data不足16的整数倍,填充规则是可以自己规定的,同一原文填充规则不同,得到的密文也不同。

在此贴出部分OC处理sm4加密方法

   //原数据长度
    NSUInteger plainDataLength = plainData.length;
    int sm4Length = (int)(plainDataLength);
    //申请内存并填充
    unsigned char *plainChar = malloc(sm4Length);
    if (plainChar == NULL) {
        return nil;
    }
    memcpy(plainChar, plainData.bytes, plainDataLength);
    //申请内存
    unsigned char *cipherChar = malloc(sm4Length);
    if (cipherChar == NULL) {
        free(plainChar);
        return nil;
    }
    //加密
    sm4_context ctx;
    sm4_setkey_enc(&ctx, (unsigned char*)keyData.bytes);
    sm4_crypt_ecb(&ctx, SM4_ENCRYPT, sm4Length, plainChar, cipherChar);
    //处理加密的输出数组为Data
    NSData *chipherData = [[NSData alloc] initWithBytes:cipherChar length:sm4Length];
    //释放内存
    free(plainChar);
    free(cipherChar);
    return chipherData;

2、CBC模式

国密sm4 ECB、CEC模式探究与在iOS中的应用_第2张图片

CBC(密文分组链接方式),它的实现机制使加密的各段数据之间有了联系。

也是按照data 16位来分组,第一组数据与初始化向量IV异或后的结果进行加密,密得到第一组密文C1(初始化向量I为全零),第二组数据与第一组的加密结果C1异或以后的结果进行加密,得到第二组密文C2...... 最后C1C2C3......Cn即为加密结果。

此种方法安全性高,但是不利于并行计算,有误差传递,需要初始化向量IV

展示部分代码

调用

  sm4_crypt_cbc(&ctx, SM4_ENCRYPT, sm4Length, sm4IVChar, plainChar, cipherChar);

实现

void sm4_crypt_cbc( sm4_context *ctx,
                    int mode,
                    int length,
                    unsigned char iv[16],
                    unsigned char *input,
                    unsigned char *output )
{
    int i;
    unsigned char temp[16];

    if( mode == SM4_ENCRYPT ) //加密方法
    {
        while( length > 0 )
        {
            for( i = 0; i < 16; i++ )
                output[i] = (unsigned char)( input[i] ^ iv[i] ); //异或运算

            sm4_one_round( ctx->sk, output, output );
            memcpy( iv, output, 16 ); //更改iv

            input  += 16;
            output += 16;
            length -= 16;
        }
    }
    else /* SM4_DECRYPT */
    {
        while( length > 0 )
        {
            memcpy( temp, input, 16 );
            sm4_one_round( ctx->sk, input, output );

            for( i = 0; i < 16; i++ )
                output[i] = (unsigned char)( output[i] ^ iv[i] );

            memcpy( iv, temp, 16 );

            input  += 16;
            output += 16;
            length -= 16;
        }
    }
}

其中

            output[i] = (unsigned char)( input[i] ^ iv[i] ); //异或运算

            sm4_one_round( ctx->sk, output, output );
            memcpy( iv, output, 16 ); //更改iv

这三行代码 我们也能读出 主要加密链式模式

贴出OC 调用CBC加密部分代码

//原数据长度
    NSUInteger plainDataLength = plainData.length;
    
    //获取sm4长度,必须是16的整数倍(16个字节,128bit)
    NSUInteger p = SM4_BLOCK_SIZE - plainDataLength % SM4_BLOCK_SIZE;
    int sm4Length = (int)(plainDataLength + p);
    //申请内存
    unsigned char *plainChar = malloc(sm4Length);
    if (plainChar == NULL) {
        return nil;
    }
    memcpy(plainChar, plainData.bytes, plainDataLength);
    
    //补充位填充扩展了多少位,解密时用到
    for (int i=0; i         plainChar[plainDataLength + i] = p;
    }
    
    //加密输出数组
    unsigned char *cipherChar = malloc(sm4Length);
    if (cipherChar == NULL) {
        free(plainChar);
        return nil;
    }
    
    //复制IV值
    unsigned char sm4IVChar[SM4_BLOCK_SIZE];
    memcpy(sm4IVChar, IV.bytes, SM4_BLOCK_SIZE);
    
    //执行加密
    sm4_context ctx;
    sm4_setkey_enc(&ctx, (unsigned char *)keyData.bytes);
    sm4_crypt_cbc(&ctx, SM4_ENCRYPT, sm4Length, sm4IVChar, plainChar, cipherChar);
    
    //处理加密输出数组为Data
    NSData *cipherData = [[NSData alloc] initWithBytes:cipherChar length:sm4Length];
    
    //释放内存
    free(plainChar);
    free(cipherChar);
    
    return cipherData;
  

稍微会继续分析sm2加解密、加签延签流程

与分享sm2 sm3 sm4 在iOS中的封装库

 

 

你可能感兴趣的:(国密,sm4,ios)