⚠ This page is served via a proxy. Original site: https://github.com
This service does not collect credentials or authentication data.
Skip to content

some NSData Category for doing RSA,AES,MD5,SHA1,SHA256,Sign,Verify on iOS Cryptography

Notifications You must be signed in to change notification settings

cocoajin/Security-iOS

Repository files navigation

Security-iOS

封装了一些iOS上使用的NSData分类,主要用于 RSA加密,AES加密,数据签名,签名校验,MD5 SHA1 SHA256 常用hash等工具。

主要使用的是iOS上 Security.frameworkCommonCrypto 接口

支持iOS2.0+开发

md5,sha1,sha256常用hash

接口文件和源码 NSData+KKHASH.h,NSData+KKHASH.m

支持的hash算法有

typedef enum : NSUInteger {
    //md2 16字节长度
    CCDIGEST_MD2 = 1000,
    //md4 16字节长度
    CCDIGEST_MD4,
    //md5 16字节长度
    CCDIGEST_MD5,
    //sha1 20字节长度
    CCDIGEST_SHA1,
    //SHA224 28字节长度
    CCDIGEST_SHA224,
    //SHA256 32字节长度
    CCDIGEST_SHA256,
    //SHA384 48字节长度
    CCDIGEST_SHA384,
    //SHA512 64字节长度
    CCDIGEST_SHA512,
} CCDIGESTAlgorithm;

调用接口

/**
    计算数据的hash值,根据不同的算法
 */
- (NSData *)hashDataWith:(CCDIGESTAlgorithm )ccAlgorithm;


/**
    返回 hex string的 data
 */
- (NSString *)hexString;

调用示例

//测试哈希函数
- (void)testKKHASHTools
{
    //以下结果由openssl dtsg 命令得出的结果,并和这里相比对
    NSString *tpath = [[NSBundle mainBundle] pathForResource:@"src.txt" ofType:nil];
    NSData *test = [NSData dataWithContentsOfFile:tpath];
    NSLog(@"%@",[[test hashDataWith:CCDIGEST_MD2] hexString]);
    if([[[test hashDataWith:CCDIGEST_MD4] hexString] isEqualToString:@"a695ea9f14a89c4e82ca5cf52a28d45d"])
    {
        NSLog(@"MD4 TEST PASS");
    }
    if([[[test hashDataWith:CCDIGEST_MD5] hexString] isEqualToString:@"781e5e245d69b566979b86e28d23f2c7"])
    {
        NSLog(@"MD5 TEST PASS");
    }
    if([[[test hashDataWith:CCDIGEST_SHA1] hexString] isEqualToString:@"87acec17cd9dcd20a716cc2cf67417b71c8a7016"])
    {
        NSLog(@"SHA1 TEST PASS");
    }
    if([[[test hashDataWith:CCDIGEST_SHA224] hexString] isEqualToString:@"f28ad8ecd48ba6f914c114821685ad08f0d6103649ff156599a90426"])
    {
        NSLog(@"SHA224 TEST PASS");
    }
    if([[[test hashDataWith:CCDIGEST_SHA256] hexString] isEqualToString:@"84d89877f0d4041efb6bf91a16f0248f2fd573e6af05c19f96bedb9f882f7882"])
    {
        NSLog(@"SHA256 TEST PASS");
    }
    if([[[test hashDataWith:CCDIGEST_SHA384] hexString] isEqualToString:@"90ae531f24e48697904a4d0286f354c50a350ebb6c2b9efcb22f71c96ceaeffc11c6095e9ca0df0ec30bf685dcf2e5e5"])
    {
        NSLog(@"SHA384 TEST PASS");
    }
    if([[[test hashDataWith:CCDIGEST_SHA512] hexString] isEqualToString:@"bb96c2fc40d2d54617d6f276febe571f623a8dadf0b734855299b0e107fda32cf6b69f2da32b36445d73690b93cbd0f7bfc20e0f7f28553d2a4428f23b716e90"])
    {
        NSLog(@"SHA512 TEST PASS");
    }

}

AES 加密解密

接口文件和源码 NSData+KKAES.h,NSData+KKAES.m

支持AES cbc,ecb两种模式,默认使用的填充方式 kCCOptionPKCS7Padding. 可以参考更多 iOS CommonCrypto 对称加密 AES ecb,cbc

主要接口

/**
    AES cbc 模式加密,
    @key 长度16字节,24字节,32字节
    @iv 16字节
 */
- (NSData *)AES_CBC_EncryptWith:(NSData *)key iv:(NSData *)iv;

/**
    AES cbc 模式解密,
    @key 长度16字节,24字节,32字节
    @iv 16字节
 */
- (NSData *)AES_CBC_DecryptWith:(NSData *)key iv:(NSData *)iv;

/**
    AES ecb 模式加密,
    @key 长度16字节,24字节,32字节
 */
- (NSData *)AES_ECB_EncryptWith:(NSData *)key;

/**
    AES ecb 模式解密,
    @key 长度16字节,24字节,32字节
 */
- (NSData *)AES_ECB_DecryptWith:(NSData *)key;

调用示例

    NSData *key16 = [@"0123456789123456" dataUsingEncoding:NSUTF8StringEncoding];
    NSData *key24 = [@"012345678901234567891234" dataUsingEncoding:NSUTF8StringEncoding];
    NSData *key32 = [@"01234567890123456789012345678912" dataUsingEncoding:NSUTF8StringEncoding];
    NSData *iv16 = [@"0123456789654321" dataUsingEncoding:NSUTF8StringEncoding];
    NSData *srcData = [@"this is src test data" dataUsingEncoding:NSUTF8StringEncoding];
    NSLog(@"%@",srcData);
    
    
    
    NSData *dec16 = [[srcData AES_CBC_EncryptWith:key16 iv:iv16] AES_CBC_DecryptWith:key16 iv:iv16];
    if (memcmp(srcData.bytes, dec16.bytes, srcData.length)==0) {
        NSLog(@"AES_cbc_16 PASS");
    }
    
    
    NSData *dec24 = [[srcData AES_CBC_EncryptWith:key24 iv:iv16] AES_CBC_DecryptWith:key24 iv:iv16];
    if (memcmp(srcData.bytes, dec24.bytes, srcData.length)==0) {
        NSLog(@"AES_cbc_24 PASS");
    }
    
    
    NSData *dec32 = [[srcData AES_CBC_EncryptWith:key32 iv:iv16] AES_CBC_DecryptWith:key32 iv:iv16];
    if (memcmp(srcData.bytes, dec32.bytes, srcData.length)==0) {
        NSLog(@"AES_cbc_32 PASS");
    }
    
    
    
    
    NSData *edec16 = [[srcData AES_ECB_EncryptWith:key16] AES_ECB_DecryptWith:key16];
    if (memcmp(srcData.bytes, edec16.bytes, srcData.length)==0) {
        NSLog(@"AES_ecb_16 PASS");
    }
    
    
    NSData *edec24 = [[srcData AES_ECB_EncryptWith:key24] AES_ECB_DecryptWith:key24];
    if (memcmp(srcData.bytes, edec24.bytes, srcData.length)==0) {
        NSLog(@"AES_ecb_24 PASS");
    }
    
    
    NSData *edec32 = [[srcData AES_ECB_EncryptWith:key32] AES_ECB_DecryptWith:key32];
    if (memcmp(srcData.bytes, edec32.bytes, srcData.length)==0) {
        NSLog(@"AES_ecb_32 PASS");
    }

RSA 加密解密

接口和源码 NSData+KKRSA.h,NSData+KKRSA.m

支持的RSA密钥位数:512,768,1024,2048等; 可以参考更多 iOS使用Security.framework进行RSA 加密解密签名和验证签名

支持的填充方式

//分组加密,支持最大的加密块为 block 和填充方式有关
typedef enum : NSUInteger {
    //不填充,最大数据块为 blockSize
    RSAPaddingNONE,
    //填充方式pkcs1,最大数据块为 blockSize -11
    RSAPaddingPKCS1,
    //填充方式OAEP, 最大数据块为 blockSize -42
    RSAPaddingOAEP,
} RSAPaddingTYPE;

调用接口

/**
    公钥加密
 */
- (NSData *)RSAEncryptWith:(SecKeyRef )publicKey paddingType:(RSAPaddingTYPE )pdType;

/**
    私钥解密
 */
- (NSData *)RSADecryptWith:(SecKeyRef )privateKey paddingType:(RSAPaddingTYPE )pdType;

调用示例

//生成RSA密钥对,公钥和私钥,支持的SIZE有
// sizes for RSA keys are: 512, 768, 1024, 2048.
- (void)generateRSAKeyPair:(int )keySize
{
    if (publicKeyRef) {
        return;
    }
    OSStatus ret = 0;
    publicKeyRef = NULL;
    privateKeyRef = NULL;
    ret = SecKeyGeneratePair((CFDictionaryRef)@{(id)kSecAttrKeyType:(id)kSecAttrKeyTypeRSA,(id)kSecAttrKeySizeInBits:@(keySize)}, &publicKeyRef, &privateKeyRef);
    NSAssert(ret==errSecSuccess, @"密钥对生成失败:%d",ret);
    
    NSLog(@"%@",publicKeyRef);
    NSLog(@"%@",privateKeyRef);
    NSLog(@"max size:%lu",SecKeyGetBlockSize(privateKeyRef));
    
}

    //生成密钥对
    [self generateRSAKeyPair:kRSA_KEY_SIZE];
    
    NSData *srcData = [@"01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567" dataUsingEncoding:NSASCIIStringEncoding];
    //max 128
    NSData *decData = [[srcData RSAEncryptWith:publicKeyRef paddingType:RSAPaddingNONE] RSADecryptWith:privateKeyRef paddingType:RSAPaddingNONE];
    
    if (memcmp(srcData.bytes, decData.bytes, srcData.length)==0) {
        NSLog(@"RSA RSAPaddingNONE TEST PASS");
    }
    
    
    NSData *srcData2 = [@"012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456" dataUsingEncoding:NSASCIIStringEncoding];
    //max 128-11 117
    NSData *decData2 = [[srcData2 RSAEncryptWith:publicKeyRef paddingType:RSAPaddingPKCS1]
                        RSADecryptWith:privateKeyRef paddingType:RSAPaddingPKCS1];
    
    if (memcmp(srcData2.bytes, decData2.bytes, srcData2.length)==0) {
        NSLog(@"RSA RSAPaddingPKCS1 TEST PASS");
    }
    
    
    NSData *srcData3 = [@"01234567890123456789012345678901234567890123456789012345678901234567890123456789123456" dataUsingEncoding:NSASCIIStringEncoding];
    //max 128-42 86
    NSData *decData3 = [[srcData3 RSAEncryptWith:publicKeyRef paddingType:RSAPaddingOAEP] RSADecryptWith:privateKeyRef paddingType:RSAPaddingOAEP];
    
    if (memcmp(srcData3.bytes, decData3.bytes, srcData3.length)==0) {
        NSLog(@"RSA RSAPaddingOAEP TEST PASS");
    }

RSA签名验证签名

接口文件和源码 NSData+KKSignVerify.h,NSData+KKSignVerify.m

数据签名一般签名数据的hash值,配合上面的HASH函数使用

支持的签名算法

//主要使用PKCS1 方式的填充,最大签名数据长度为blockSize-11
//签名算法从ios5以后不再支持md5,md2
typedef enum : NSUInteger {
    SEC_PKCS1SHA1 = 2000,
    SEC_PKCS1SHA224,
    SEC_PKCS1SHA256,
    SEC_PKCS1SHA384,
    SEC_PKCS1SHA512,
} SEC_PKCS1_ALGORITHM;

主要接口

/**
    根据不同的算法,签名数据,
 */
- (NSData *)signDataWith:(SecKeyRef)privateKey algorithm:(SEC_PKCS1_ALGORITHM )ccAlgorithm;

/**
    验证签名数据
 */
- (BOOL)verifySignWith:(SecKeyRef)publicKey signData:(NSData *)signData algorithm:(SEC_PKCS1_ALGORITHM )ccAlgorithm;

调用示例

		//生成RSA密钥对,
    [self generateRSAKeyPair:kRSA_KEY_SIZE];
    
    NSString *tpath = [[NSBundle mainBundle] pathForResource:@"src.txt" ofType:nil];
    NSData *ttDt = [NSData dataWithContentsOfFile:tpath];
    NSData *sha1dg = [ttDt hashDataWith:CCDIGEST_MD4];
    

    if ([sha1dg verifySignWith:publicKeyRef signData:[sha1dg signDataWith:privateKeyRef algorithm:SEC_PKCS1SHA1] algorithm:SEC_PKCS1SHA1]) {
        NSLog(@"SIGN-VERIFY sha1 PASS");
    }
    
    if ([sha1dg verifySignWith:publicKeyRef signData:[sha1dg signDataWith:privateKeyRef algorithm:SEC_PKCS1SHA224] algorithm:SEC_PKCS1SHA224]) {
        NSLog(@"SIGN-VERIFY sha224 PASS");
    }
    
    if ([sha1dg verifySignWith:publicKeyRef signData:[sha1dg signDataWith:privateKeyRef algorithm:SEC_PKCS1SHA256] algorithm:SEC_PKCS1SHA256]) {
        NSLog(@"SIGN-VERIFY sha256 PASS");
    }
    
    if ([sha1dg verifySignWith:publicKeyRef signData:[sha1dg signDataWith:privateKeyRef algorithm:SEC_PKCS1SHA384] algorithm:SEC_PKCS1SHA384]) {
        NSLog(@"SIGN-VERIFY sha384 PASS");
    }
    if ([sha1dg verifySignWith:publicKeyRef signData:[sha1dg signDataWith:privateKeyRef algorithm:SEC_PKCS1SHA512] algorithm:SEC_PKCS1SHA512]) {
        NSLog(@"SIGN-VERIFY sha512 PASS");
    }

RSA密钥管理

接口文件和源码 SecKeyTools.h,SecKeyTools.m

主要用于读取密钥文件中的密钥,如从证书中读取公钥,从p12文件中读取私钥等操作; RSA相关的密钥放在手机上是不安全的,但是也没有绝对的安全,视业务情况来定吧。

主要接口

/**
    从x509 cer证书中读取公钥
 */
+ (SecKeyRef )publicKeyFromCer:(NSString *)cerFile;


/**
    从 p12 文件中读取私钥,一般p12都有密码
 */
+ (SecKeyRef )privateKeyFromP12:(NSString *)p12File password:(NSString *)pwd;


/**
    iOS 10 上可用如下接口SecKeyCreateWithData 从pem文件中读取私钥或公钥
 */
+ (SecKeyRef )publicKeyFromPem:(NSString *)pemFile keySize:(size_t )size;

+ (SecKeyRef )privaKeyFromPem:(NSString *)pemFile keySize:(size_t )size;

调用示例

    NSString *cerPA = [[NSBundle mainBundle] pathForResource:@"CPPUB.cer" ofType:nil];
    NSString *p12PA = [[NSBundle mainBundle] pathForResource:@"CPPRI.p12" ofType:nil];
    
    SecKeyRef pubkey = [SecKeyTools publicKeyFromCer:cerPA];
    SecKeyRef prikey = [SecKeyTools privateKeyFromP12:p12PA password:@"test"];

    NSLog(@"%@",pubkey);
    NSLog(@"%@",prikey);
    
    NSLog(@"%lu",SecKeyGetBlockSize(prikey));
    
    
    NSData *srcData = [@"0123456789" dataUsingEncoding:NSUTF8StringEncoding];
    NSLog(@"%@",srcData);
    NSData *encDT = [srcData RSAEncryptWith:pubkey paddingType:RSAPaddingPKCS1];
    NSData *decDT = [encDT RSADecryptWith:prikey paddingType:RSAPaddingPKCS1];
    NSLog(@"%@",decDT);
    
    
    
    NSString *pripem = [[NSBundle mainBundle] pathForResource:@"private.pem" ofType:nil];
    NSString *pubpem = [[NSBundle mainBundle] pathForResource:@"public.pem" ofType:nil];
    SecKeyRef pubKK = [SecKeyTools publicKeyFromPem:pubpem keySize:kRSA_KEY_SIZE];
    SecKeyRef priKK = [SecKeyTools privaKeyFromPem:pripem keySize:kRSA_KEY_SIZE];
    NSLog(@"%@",pubKK);
    NSLog(@"%@",priKK);
    
    NSLog(@"%lu",SecKeyGetBlockSize(priKK));
    NSData *srcData2 = [@"0123456789" dataUsingEncoding:NSUTF8StringEncoding];
    NSLog(@"%@",srcData2);
    NSData *encDT2 = [srcData2 RSAEncryptWith:pubKK paddingType:RSAPaddingPKCS1];
    NSData *decDT2 = [encDT2 RSADecryptWith:priKK paddingType:RSAPaddingPKCS1];
    NSLog(@"%@",decDT2);

其他

  • 密钥对的生成
//生成RSA密钥对,公钥和私钥,支持的SIZE有
// sizes for RSA keys are: 512, 768, 1024, 2048.
- (void)generateRSAKeyPair:(int )keySize
{
    if (publicKeyRef) {
        return;
    }
    OSStatus ret = 0;
    publicKeyRef = NULL;
    privateKeyRef = NULL;
    ret = SecKeyGeneratePair((CFDictionaryRef)@{(id)kSecAttrKeyType:(id)kSecAttrKeyTypeRSA,(id)kSecAttrKeySizeInBits:@(keySize)}, &publicKeyRef, &privateKeyRef);
    NSAssert(ret==errSecSuccess, @"密钥对生成失败:%d",ret);
    
    NSLog(@"%@",publicKeyRef);
    NSLog(@"%@",privateKeyRef);
    NSLog(@"max size:%lu",SecKeyGetBlockSize(privateKeyRef));
    
}
  • RSA上几种填充方式的区别
/** 三种填充方式区别
 kSecPaddingNone      = 0,   要加密的数据块大小<=SecKeyGetBlockSize的大小,如这里128
 kSecPaddingPKCS1     = 1,   要加密的数据块大小<=128-11
 kSecPaddingOAEP      = 2,   要加密的数据块大小<=128-42
  密码学中的设计原则,一般用RSA来加密 对称密钥,用对称密钥加密大量的数据
  非对称加密速度慢,对称加密速度快
 */
  • 示例工程 SecurityiOS.xcodeproj

About

some NSData Category for doing RSA,AES,MD5,SHA1,SHA256,Sign,Verify on iOS Cryptography

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published