前言
现在人们对于个人信息的隐私保护意识也是越来越强烈了,在移动互联网中,对于数据的加密也是必不可少的。不过对于作者本人来说,之前涉及到数据加密的这一块可能不是多。最近就是在做项目需求的时候有涉及到加密,今天就来出一篇文章记录一下
GMObjc
当时我们的加密要求是要做一个SM2加密,所以当我接到任务的时候就很习惯的去了github上看看有没有人做过相关的需求,最好就是有现成的库可以供我使用。这不GMobjc就这么的被我发现了。
集成方式
在文章中写得很清楚,这个库提供了多种集成方式,你也可以根据项目的类型,选择适合你们项目的集成方式。个人认为CocoaPods
这种方式是最为简单便捷的。不用关心项目的配置问题和OpenSSL的冲突问题。
我们是使用的手动集成的方式,我们选择直接导入了源代码中的FrameWorks
文件夹下面的GMObjc.xcframework
中的iOS-arm64
文件夹下的GMObjc.framework
。
一方面我们的项目不需要在模拟器上面做调试,现在x86架构的设备也不在项目的支持范围内,另一方面也是为了一进步的减少包体积。
SM2加密解密
想要做数据加密,肯定是少不了秘钥的。项目肯定是有自己设计好的公钥和私钥。不过GMObjc也提供了自己生成密钥的API。个人估计就是想让你试试能不能正常的对数据进行加密解密做测试,相信应该也不会有很多人直接用这个API到自己的项目中。
objc
/**
SM2 加解密及签名的 OC 封装
@interface GMSm2Utils : NSObject
// MARK: - 创建秘钥对
/// 创建 SM2 公私钥(基于官方文档 NID_*sm2 推荐曲线)。返回值:公钥和私钥 HEX 编码字符串***
+ (GMSm2Key *)generateKey;
// MARK: - 加密
/// SM2 加密。返回 ASN1 编码密文(ASN1 编码可使用 asn1DecodeToC1C3C2Data 解码为非 ASN1 编码),失败返回 nil
/// @param plainData 明文(NSData 格式)
/// @param publicHex 04 开头的公钥( HEX 编码格式)
+ (nullable NSData *)encryptData:(NSData *)plainData publicKey:(NSString *)publicHex;
/// SM2 加密。返回 ASN1 编码密文(ASN1 编码可使用 asn1DecodeToC1C3C2Hex 解码为非 ASN1 编码),失败返回 nil
/// @param plaintext 明文(NSString 原文格式)
/// @param publicHex 04 开头的公钥( HEX 编码格式)
+ (nullable NSString *)encryptText:(NSString *)plaintext publicKey:(NSString *)publicHex;
// MARK: - 解密
/// SM2 解密。返回 NSData 格式明文,解密失败返回 nil
/// @param asn1Data NSData 格式密文(ASN1 编码,若非 ASN1 编码,需要先使用 asn1EncodeWithC1C3C2Data 进行编码)
/// @param privateHex 私钥( HEX 编码格式)
+ (nullable NSData *)decryptData:(NSData *)asn1Data privateKey:(NSString *)privateHex;
/// SM2 解密。返回字符串格式明文,解密失败返回 nil
/// @param asn1Hex ASN1 编码密文(ASN1 编码,若非 ASN1 编码,需要先使用 asn1EncodeWithC1C3C2Hex 进行编码)
/// @param privateHex 私钥( HEX 编码格式)
+ (nullable NSString *)decryptHex:(NSString *)asn1Hex privateKey:(NSString *)privateHex;
// MARK: - ASN1 编码解码
/// ASN1 编码。返回 ASN1 编码的密文
/// @param c1c3c2Data 按照 C1C3C2 排序的 NSData 密文数据,若非此顺序需要先转换
/// @param hasPrefix 标记密文 c1c3c2Data 前面是否有前缀标识,例如 0x04 前缀标识,默认 NO
+ (nullable NSData *)asn1EncodeWithC1C3C2Data:(NSData *)c1c3c2Data hasPrefix:(BOOL)hasPrefix;
/// ASN1 编码。返回 ASN1 编码的密文( HEX 编码格式)
/// @param c1c3c2Hex 按照 C1C3C2 排序的 16 进制编码密文数据,若非此顺序需要先转换
/// @param hasPrefix 标记密文 c1c3c2Hex 前面是否有前缀标识,例如 04 前缀标识,默认 NO
+ (nullable NSString *)asn1EncodeWithC1C3C2Hex:(NSString *)c1c3c2Hex hasPrefix:(BOOL)hasPrefix;
/// ASN1 解码。返回按照 C1C3C2 排序的密文,hasPrefix=YES时,返回结果前面会拼接上 0x04 前缀标识
/// @param asn1Data ASN1 编码的密文
/// @param hasPrefix 返回的密文结果前面是否增加 0x04 前缀标识,YES 时返回结果前面会拼接上 0x04,默认 NO
+ (nullable NSData *)asn1DecodeToC1C3C2Data:(NSData *)asn1Data hasPrefix:(BOOL)hasPrefix;
/// ASN1 解码。返回按照 C1C3C2 排序的密文(HEX 编码格式),hasPrefix=YES时,返回结果前面会拼接上 04 前缀标识
/// @param asn1Hex ASN1 编码的密文 (HEX 编码格式)
/// @param hasPrefix 返回的密文结果前面是否增加 04 前缀标识,YES 时返回结果前面会拼接上 04,默认 NO
+ (nullable NSString *)asn1DecodeToC1C3C2Hex:(NSString *)asn1Hex hasPrefix:(BOOL)hasPrefix;
@end
在这里调用加密的方式有两种,一种是直接的对字符串加密,另一种是对data加密,这个你需要根据项目需求你们最后需要的是一个什么格式的参数而决定。而且需要注意的是,加密出来的一个ASN1
格式的编码。你还需要对这个编码再进行一次解码操作才可以。
objc
NSString *asn1 = [GMSm2Utils encryptText:@"63012" publicKey:@"publicKey"];
NSString *c1c3c2 = [GMSm2Utils asn1DecodeToC1C3C2Hex:asn1 hasPrefix:NO];
总结
这个库用起来还是很简单明了的。不过在这次集成的过程中还是遇到了一些问题的。
1.如果你是源代码的那种集成方式,在集成源代码和OpenSSL的同时,你还要注意一下项目是不是还有别的库也有用到OpenSSL。因为就算不冲突运行之后,通过相同的公钥解密出来的秘文,服务端也有可能不能通过私钥解密。 2.如果和我一样是集成的framework 别忘了在Framework、Libraries、and Embedded Content
找到GMObjc.framework
后边的选项改成Embed and Sign