相对于另一种更好的加密实现,本文方法容易受干扰
尽量使用我另一篇博客介绍的https://blog.csdn.net/qq_15509071/article/details/107832587 这个开源密码箱来实现








SM2是一种非对称秘钥加密算法。用最明白的话说:

  1. 从一个私钥可以生成唯一一个公钥(不考虑随机数,在这里把随机数固定),所以测试工具里先输入私钥再点击生成秘钥对
  2. 一个公钥可以找出很多私钥
  3. 加密时输入的参数是:公钥和明文,输出:密文
  4. 解密时输入参数是:私钥和密文,输出:明文
  5. 选择一样的曲线,在官网的示例中有两条曲线,最后推荐的又是另一种曲线,网上的很多测试工具都是基于推荐曲线做的。官网链接 http://www.oscca.gov.cn/News/201012/News_1198.htm
  6. 公钥是坐标点:P(Px,Py)
  7. 网上的测试工具有的输入输出都是16进制的,有的输入输出都是10进制的,要一致
  8. 加密时也会用随机数,如果随机数固定,则公钥也是固定的,密文也是固定的
  9. SM2分为秘钥交换,签名验证,公钥加密,网上的好多代码都是前两个,没有公钥加密,本文写的就是公钥加密
  10. 我用的sm2的c语言代码的下载地址是:http://download.csdn.net/detail/jk0o0/7834347#comment
  11. 密文分为C1,C2,C3,三部分,C1长度是64,C2是明文的长度,C3是32位
  12. C1 || C2 || C3 的意思就是拼在一起,而不是做什么或运算


现在把第10点的代码集合到自己的工程:

1.将不需要的文件删除,即下图红方框里的文件

注意:这些文件的编码格式不是utf8的,在xcode里面中文会显示成乱码,这些中文注释一定要看,在Windows系统下看。

2.导入到ios工程里,编译报错,没有openssl/ec.h这个文件

3.查一下什么是openssl,是关于密码的第三方开源库,然后需要把它集成到我们工程里。

3.1到https://github.com/x2on/OpenSSL-for-iPhone下载下来,是1.0.2版本的。下载后的文件是:

3.2只看build-libssl.sh文件,打开mac电脑的终端程序,将这个sh文件直接拖到终端里

3.3点回车,它会自动下载openssl的源代码并生成多个指令集的静态库。当然需要10分钟左右时间

3.4 openssl的源代码和编译好的静态库在mac电脑的根目录下: /Users/用户名/OpenSSL_1_0_2h.tar.gz

3.5在3.4的bin目录下就是编译好的静态库,包括

3.6 以iPhoneOS9.3-arm64.sdk文件夹为例:

3.7 lib目录下的libcrypto.a和libssl.a是生成的静态库,include目录下的openssl文件夹是对应的头文件。

3.8这个是arm64的库,如果同时需要支持armv7 arm64 则要将两个静态库合成一个,用命令:lipo -create /Users/yyy/Desktop/合到一起/libcrypto7.a /Users/yyy/Desktop/合到一起/libcrypto64.a -output /Users/yyy/Desktop/合到一起/libcrypto.a

3.9将这三个文件导入到我们工程里,编译一下,报错还是和之前一样:‘openssl/ec.h’ file not found。点击xcode工程的搜索和替换,填写下面信息,点全部替换

4编译一下,报错
duplicate symbol _main in: SM2.o main.o

5.将sm2.c里面的main函数改名为mianSM2, 现在编译通过。

上面的中文注释很重要!只看part4是SM2公钥加密,

这四个是官网的示例曲线
sm2_param_fp_192,
sm2_param_fp_256,
sm2_param_f2m_193,
sm2_param_f2m_257,
这个是官网推荐曲线,用这个
sm2_param_recommand

在工程里需要的地方调用
test_part4(sm2_param_recommand, TYPE_GFp, 256);
这个方法。

5在编译可能会报错

把RSA改成RSA_Y
6.这是控制台的输出:

key_B->d:
1649AB77 A00637BD 5E2EFE28 3FBF3535 34AA7F7C B89463F2 08DDBC29 20BB0DA0
key_B->P->x:
191BFF81 48006EEA 72D857CB 974DB9F4 903B3CA3 655D8D59 7AD4663F 5044DCB1
key_B->P->y:
E2F7888A F1FCD8C6 53A8059C D2F37985 5389F71A 7709E2C1 EE1E914C 855EF119
(BYTE *)H:
B2054BCB 433B430C F6141BCF 2C98F617 7C78C6E5 ED5F953E E92B1F70 AAF70233
encrypt:
message_data->C_2:
D76B28B9 3A4B3765 997A3BBC 58F99873 1D0AA2
d:
1649AB77 A00637BD 5E2EFE28 3FBF3535 34AA7F7C B89463F2 08DDBC29 20BB0DA0
xy2->x:
B18FE085 4DAF664D 357BD2DA 38714F02 026CF4A7 62BEFF0C DEFEE1AF 002DA0EE
xy2->y:
38ED9760 EF652F28 B81732B9 6247E135 87642E30 D9DFA9B3 C307A092 E415B07F
(BYTE *)H:
B2054BCB 433B430C F6141BCF 2C98F617 7C78C6E5 ED5F953E E92B1F70 AAF70233
decrypt: len: 19
encryption standard

key_B->d:私钥
key_B->P->x:公钥x
key_B->P->y:公钥y
(BYTE *)H:t
message_data->C_2:C2

有几个问题:
1.输出的长度不全(输出C,C1时)
2.这个方法加密解密是放在一起的
3.明文输入的是字符串,而不是16进制的char数组

7.把这个方法分成加密和解密两个方法

void sm2JiaMi(char **sm2_param, int type, int point_bit_length , char *mingwen,char *miwen){ec_param *ecp;sm2_ec_key *key_B;message_st message_data;ecp = ec_param_new();ec_param_init(ecp, sm2_param, type, point_bit_length);key_B = sm2_ec_key_new(ecp);//用私钥和随机数导出一个公钥,实际应用时没有私钥,也就是没有这行代码,直接设置下面的公钥sm2_ec_key_init(key_B, sm2_param_d_B[ecp->type], ecp);//把中间的值给key_b的bmemset(&message_data, 0, sizeof(message_data));
//设置明文 这里输入一个字符串 如果输入char[]需要稍微改动message_data.message = (BYTE *)mingwen;message_data.message_byte_length = (int)strlen((char *)message_data.message);message_data.klen_bit = message_data.message_byte_length * 8;//随机数 拷贝到message_data.k,实际使用时应该随机生成这个数sm2_hex2bin((BYTE *)sm2_param_k[ecp->type], message_data.k, ecp->point_byte_length);//设置公钥sm2_bn2bin(key_B->P->x, message_data.public_key.x, ecp->point_byte_length);sm2_bn2bin(key_B->P->y, message_data.public_key.y, ecp->point_byte_length);DEFINE_SHOW_BIGNUM(key_B->P->x);//公钥PB =(xB ,yB ): 坐标xB :DEFINE_SHOW_BIGNUM(key_B->P->y);//坐标yB :
//加密sm2_encrypt(ecp, &message_data);memcpy(miwen, message_data.C, sizeof(message_data.C));sm2_ec_key_free(key_B);ec_param_free(ecp);}
void sm2Jiemi(char **sm2_param, int type, int point_bit_length , char *miwen ,char output[] ){ec_param *ecp;sm2_ec_key *key_B;message_st message_data;//ecp的开辟空间p a b necp = ec_param_new();//ecp 给 pabn设置标准值ec_param_init(ecp, sm2_param, type, point_bit_length);//给dp开辟空间key_B = sm2_ec_key_new(ecp);//设置私钥,把中间的值给key_b的bsm2_ec_key_init(key_B, sm2_param_d_B[ecp->type], ecp);memset(&message_data, 0, sizeof(message_data));//明文的长度,这个长度应该根据密文计算,这里固定写6message_data.message_byte_length = 6;//k的比特长度是明文长度*8message_data.klen_bit = message_data.message_byte_length * 8;//设置私钥,解密和公钥和随机数无关sm2_bn2bin(key_B->d, message_data.private_key, ecp->point_byte_length);//私钥dB :DEFINE_SHOW_BIGNUM(key_B->d);//给解密后的明文开辟空间message_data.decrypt = (BYTE *)OPENSSL_malloc(message_data.message_byte_length + 1);memset(message_data.decrypt, 0, message_data.message_byte_length+1);//置为0//设置密文for (int i = 0; i < 256; i++){message_data.C[ i] =  miwen[i];}DEFINE_SHOW_STRING(message_data.C, 256);sm2_decrypt(ecp, &message_data);memcpy(output, message_data.decrypt, 100);OPENSSL_free(message_data.decrypt);sm2_ec_key_free(key_B);ec_param_free(ecp);
}
这是如何在ios工程调用上面两个方法NSString *mingwen = @"123456";char miwen[1024];sm2JiaMi(sm2_param_recommand, TYPE_GFp, 256, [mingwen UTF8String], miwen);//密文前面多个04  在用其他工具对密文解密时需要去掉NSData *miwendata =  [[NSData alloc]initWithBytes:miwen length: mingwen.length+32+64 +2];NSLog(@"密文data=%@",  miwendata );//解密和加密类似将char数组转成nsdata再转成nsstringchar output[100];sm2Jiemi(sm2_param_recommand, TYPE_GFp, 256, miwen,output);NSString *mingwenout = [[NSString alloc]initWithCString:output encoding:NSUTF8StringEncoding];NSLog(@"---解密后%@---",mingwenout);

如果需要传入自己公钥加密,则加密方法要相应改一下

//使用传入的公钥加密
void sm2JiaMiWithPublicKey(char **sm2_param, int type, int point_bit_length , char mingwen[],char *miwen,unsigned char px[],unsigned char py[]){ec_param *ecp;sm2_ec_key *key_B;message_st message_data;ecp = ec_param_new();ec_param_init(ecp, sm2_param, type, point_bit_length);key_B = sm2_ec_key_new(ecp);sm2_ec_key_init(key_B, sm2_param_d_B[ecp->type], ecp);memset(&message_data, 0, sizeof(message_data));message_data.message = (BYTE*)mingwen;
//    memcpy(message_data.message, mingwen,strlen(mingwen) );message_data.message_byte_length = 8;message_data.klen_bit = message_data.message_byte_length * 8;//这个是固定的随机数//sm2_hex2bin((BYTE *)sm2_param_k[ecp->type], message_data.k, ecp->point_byte_length);//随机数种子static const char rnd_seed[] = "random num c random num seed random num c random num seed";RAND_seed(rnd_seed, sizeof rnd_seed);unsigned char suijishu[32];//生成随机数RAND_pseudo_bytes(suijishu,32);for( int i=0;i<sizeof suijishu;i++){//printf("%02x", suijishu[i]);message_data.k[i]=suijishu[i];}printf("\n");DEFINE_SHOW_STRING(message_data.k, sizeof(message_data.k));//设置px//printf("px\n");for( int i=0;i<32;i++){//printf("%02x", px[i]);message_data.public_key.x[i]=px[i];}//printf("\n");//设置py//printf("py\n");for( int i=0;i<32;i++){//printf("%02x", py[i]);message_data.public_key.y[i]=py[i];}//printf("\n");DEFINE_SHOW_BIGNUM(key_B->P->x);//公钥PB =(xB ,yB ): 坐标xB :DEFINE_SHOW_BIGNUM(key_B->P->y);//坐标yB :DEFINE_SHOW_STRING(message_data.public_key.x, 32);DEFINE_SHOW_STRING(message_data.public_key.y, 32);sm2_encrypt(ecp, &message_data);memcpy(miwen, message_data.C, sizeof(message_data.C));sm2_ec_key_free(key_B);ec_param_free(ecp);
}

调用方法是

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {//使用固定的公钥加密
//    NSString *mingwen = @"123456";
//    char miwen[1024];
//    sm2JiaMi(sm2_param_recommand, TYPE_GFp, 256, [mingwen UTF8String], miwen);
//    //密文前面多个04  在用其他工具对密文解密时需要去掉
//    NSData *miwendata =  [[NSData alloc]initWithBytes:miwen length: mingwen.length+32+64 +2];
//    NSLog(@"密文data=%@",  miwendata );//使用自己已知的公钥加密NSString *mingwen = @"123456";char miwen[1024];NSString *px_ = [@"F5AB4BCC 007AF4C3 862CF413 57C035AE 090B39B3 A7204E2D E888753E 99EC507A" stringByReplacingOccurrencesOfString:@" " withString:@""];NSString *py_ = [@"BE394FC1 0F50FC59 F6586DF7 B493150E 5DF7F575 BC1214FE D849E967 D15993FF" stringByReplacingOccurrencesOfString:@" " withString:@""];NSData *px_data = [self dataFromHexString:px_];NSData *py_data = [self dataFromHexString:py_];sm2JiaMiWithPublicKey(sm2_param_recommand, TYPE_GFp, 256, [mingwen UTF8String], miwen, px_data.bytes,py_data.bytes);//密文前面多个04  在用其他工具对密文解密时需要去掉NSData *miwendata = [[NSData alloc]initWithBytes:miwen length: mingwen.length+32+64 +2];NSLog(@"密文data=%@", miwendata );//解密和加密类似将char数组转成nsdata再转成nsstringchar output[100];sm2Jiemi(sm2_param_recommand, TYPE_GFp, 256, miwen,output);NSString *mingwenout = [[NSString alloc]initWithCString:output encoding:NSUTF8StringEncoding];NSLog(@"---解密后%@---",mingwenout);return YES;
}
- (NSData *)dataFromHexString:(NSString *)input {const char *chars = [input UTF8String];int i = 0;NSUInteger len = input.length;NSMutableData *data = [NSMutableData dataWithCapacity:len / 2];char byteChars[3] = {'\0','\0','\0'};unsigned long wholeByte;while (i < len) {byteChars[0] = chars[i++];byteChars[1] = chars[i++];wholeByte = strtoul(byteChars, NULL, 16);[data appendBytes:&wholeByte length:1];}return data;
}

发现有崩溃,把char miwen[100] 改成 char miwen[1024]即可,文章中已修改(20170112)

// 增加使用自定义私钥解密,加解密时04的处理 明文不限制位数
http://download.csdn.net/detail/qq_15509071/9784753 (20170317)

.
.

整合后的最新代码20181108

https://github.com/XiaoHeHe1/SM2_Encrypt_in_iOS/tree/master

注:如使用最新版本的openssl,工程需要有一些小改动(20211022)

在iOS中调用C语言的国密算法SM2以替换RSA相关推荐

  1. CITA v0.18 新增「基于 Rust 语言的国密算法库」新特性

    近日,秘猿科技宣布开源第一个基于 Rust 语言的国密算法代码库,以及对该算法支持友好的 CITA v0.18 版本.随着社会信息化程度的不断提升,各国对于本国的密码算法及标准均上升到国家战略的高度. ...

  2. 国密算法 SM2公钥密码 SM3杂凑算法 SM4分组密码 python代码完整实现

    包含SM2公钥密码.SM3杂凑算法和SM4分组密码的国密算法完整工具包完成了.此前分别发布过上述三个算法的代码: SM2:国密算法 SM2 公钥加密 非对称加密 数字签名 密钥协商 python实现完 ...

  3. 国密算法SM2证书制作

    原文链接:http://www.jonllen.com/jonllen/work/162.aspx 国密算法SM2证书制作 分类:工作 大中小 前段时间将系统的RSA算法全部升级为SM2国密算法,密码 ...

  4. 国密算法(SM2,SM3,SM4)完善与算法辅助工具开发

    国密算法SM2,SM3和改名发布的SM4的应用好像越来越多了.首先是国密SM2证书的升级,国内CA服务商要完成SM2算法证书支持,之后是国密算法在金融领域进行推广,新近编订的PBOC标准的增强安全部分 ...

  5. 国密算法—SM2介绍及基于BC的实现

    国密算法-SM2介绍及基于BC的实现 文章目录 国密算法-SM2介绍及基于BC的实现 简介 私钥 公钥 数据格式 密钥数据格式 私钥数据格式 公钥数据格式 加密数据格式 签名数据格式 计算过程 生成密 ...

  6. c++国密算法SM2加密解密demo

    c++国密算法SM2加密解密 一.代码 一.代码 封装加密.解密接口: 加密接口: Encrpt_SM2() 解密接口:Decrypt_SM2() 加密解密结果可以和nodejs的模块sm-crypt ...

  7. 国家医保移动支付国密算法SM2签名验签、SM4加解密DLL

    国家医保移动支付国密算法SM2签名验签.SM4加解密DLL 支持医保移动支付(国家统一版), 已知省份有广西.贵州.安徽.河北.黑龙江.湖南.吉林.江苏.四川.新疆等各地方. DLL,非.net开发, ...

  8. 小程序 js 库。国密算法 sm2、sm3 和 sm4 的实现

    sm-crypto 小程序 js 库.国密算法 sm2.sm3 和 sm4 的实现. 使用此组件需要依赖小程序基础库 2.2.1 以上版本,同时依赖开发者工具的 npm 构建.具体详情可查阅官方 np ...

  9. 国密算法 SM2 SM3 SM4 及密钥生成

    国密算法 SM2 SM3 SM4 方式一:SM2密钥在线生成 SM2密钥在线生成工具 如果你没线下生成工具,可用下面2种线上生成方式之一: 1. sm2密钥在线生成(const.net.cn) 2.  ...

最新文章

  1. php 网站内容采集器 Snoopy
  2. 数字化?智能化?中国企业智能制造现状究竟如何 李炳积 工信头条 昨天
  3. .net的label的背景如何设置成为透明_新一轮广告呈现方式变革,新橱窗广告,如何收割注意力经济?...
  4. Algs4-1.4.38 3-sum的初级算法与ThreeSum性能比较
  5. 单链表实现反转的三种方法
  6. java获取spring数据源_Spring动态注册多数据源的实现方法
  7. stm32 ISP串口下载
  8. Python中的特殊方法、属性和迭代器
  9. mysql ansi unicode_Ansi 与 Unicode 字符串类型的互相转换
  10. 关于awk 中如何使用 if条件判断句
  11. 无线测温采集设备及无线测温监控系统的选型指导-安科瑞王婧
  12. 我的过错不值得原谅,麻木的岁月我还要背负多久。
  13. 严蔚敏数据结构源码及习题解析
  14. 电力 Web SCADA 工控组态编辑器
  15. List集合和ArrayList集合源码
  16. 启动项目报错 Failed to bind properties under
  17. 技术与经济之六:现代化的陷阱
  18. iphone 相关软件源
  19. 谷歌新技术:神经优化器搜索,自动找到可解释的优化方法
  20. 思维升级 | 25W运营一年色拉店,你能赚几万?

热门文章

  1. 基于MATLAB编写的GNSS_SDR(GNSS软件接收机)——自学笔记(3)
  2. Oracle Goldengate 12c打pus补丁
  3. OC中的非正式协议与正式协议的区别
  4. Panoply安装步骤(for Mac)
  5. leaflet实现自定义线、矩形和扇形的绘制
  6. wfp例子inspect说明
  7. 异常检测-统计学方法
  8. 好用的在线加密解密工具,亲测有用
  9. Pycaffe 使用集锦
  10. 非官方谷歌地图 iOS 应用遭苹果下架