iOS RSA Der-加密 P12-解密以及配合AES使用详解
在前面的文章中我有说过AES和RSA这两种加密方式,正好在前段时间再项目中有使用到,在这里再把这两种加密方式综合在一起写一下,具体到他们的使用,以及RSA各种加密文件的生成。
一: RSA各种加密相关文件生成
1、首先生成私钥(1024)
1 | $ openssl genrsa - out private_key.pem 1024 |
上面是生成了一个名为 private_key 的pem文件,也就是我们的私钥文件,他其实就是一个简单的txt文本文件而已。
2、生成证书请求文件
1 | $ openssl req - new -key private_key.pem - out rsacert.csr |
上面命令中的 private_key.pem 就是我们的私钥文件,你会根据它生成一份名为 rsacert 的 csr 文件,当然这个名字是由你定义的。回车之后他会提示你输入国家、省份、mail等信息,当然你也可以什么都不填全部回车。大致是下面图的信息:
通过上面的命令你有了一份 rsacert.csr 文件。
3、生成证书并且签名,我们设置有效期为10年,当然这个时间也是你自己定义的
1 | $ openssl x509 -req -days 3650 - in rsacert.csr -signkey private_key.pem - out rsacert.crt |
4、生成iOS要是用的公钥文件,文件格式为der格式,文件为 public_key.der (名字自己定义)
1 | $ openssl x509 -outform der - in rsacert.crt - out public_key.der |
5、生成iOS要使用的私钥,为p12格式(名字写了p.p12 这个自己定义)
1 | $ openssl pkcs12 -export - out p.p12 -inkey private_key.pem - in rsacert.crt |
这里我们需要自己注意的点:这一步会提示给私钥文件设置密码,直接输入想要设置密码即可,然后敲回车,然后再验证刚才设置的密码,再次输入密码,然后敲回车,就可以验证了,设置密码是因为在解密时,private_key.p12文件需要和这里设置的密码配合使用,因此需要牢记此密码。具体的使用砸下面的代码中我们会展示出来怎么使用。
6、要是单单的iOS加密所需要的文件我们在这里也就已经设置OK了,但安卓一般在使用公钥的使用会用pem格式的公钥,所以这里我们还是需要再处理一下,在前面我们生成的公钥是der格式的,我们在生成一份pem格式的:
1 | $ openssl rsa - in private_key.pem - out rsa_public_key.pem -pubout |
7、安卓或者Java的同学肯定也需要私钥验证配合我们加解密数据的进行相互验证的,但他们需要的私钥都是PKCS8格式的, 所以我们还需要把我们pem格式的私钥转成PKCS8格式的:
1 | $ openssl pkcs8 -topk8 - in private_key.pem - out pkcs8_private_key.pem -nocrypt |
通过上面的这么多步,我们需要的各种格式的文件我们就都创建完成了。大概如下图所示:
注意:你要查看这几个文件的内容是不同的,比如你查看rsa_public_key.pem 和 rascert.der的内容是不相同的,格式不一样内容肯定不一样,所以要验证还是以结果为主。
二:准备完成、解释一下为什么要配合使用
说说为什么要他们配合使用:
补充:它们俩之间配合使用也和它们加密的优缺点有关系,AES加密速度比较快,但安全等级没有RSA高,RSA加密运算比较复杂,但速度相对比较慢。所以让它只加密Key的话比较合适,量比较少。就不会有性能问题。
要是我们单纯的使用AES,AES都知道是对称性加密,对称性的意思就是说加密和解密用的是同一个Key,当我们移动端把数据加密完的时候我们把数据传给后端,这时候后端要想解开这个加密的数据就需要知道你是用什么Key加密的,这时候可能有同学会想,那我们和后端定义相同的Key不就OK了吗,嗯....那后端的Key就保存在哎服务器,移动端的呢?写在本地还是去服务端请求?都不可以。因为用过这两种方式那安全性就没办法保证了。你写在本地的可以反编译你的代码,要是去服务端请求那就能被人劫持,只要知道了这个Key那你的加密就变得毫无意义!但至少我们知道了一点,这个Key很重要!
很重要那我们该怎么处理呢,这时候就回到我们前面说的正题,AES和RSA配合使用,这个Key的安全性就通过我们的RSA非对对称性加密保证,对称性就是加密解密要使用同一个Key,非对称性肯定就是加密和解密不使用同一个Ke了,那就是我们的公钥和私钥,公钥加密私钥解密,把我们的Key通过公钥加密之后上传服务器,服务端拿到之后通过私钥解密就拿到了Key,再去解密我们的AES数据,有同学会想,前面说我们的AES的Key可能会被劫持,那加了密被劫持呢,放心被劫持到的也是我们通过公钥加密的,想要得知真正的Key就得知道我们的私钥,可私钥在我们服务端要想拿到除非有了间谍,不然是没法解开真正的Key。
三:解释完成,该上代码了
我们先看RSA加密的代码,代码具体的都有注释,使用时候需要我们注意的我们在下面说,下面是这个.m文件的代码:
注意:RSA加密相同的字符串每一次的结果都是不相同的,所以不能以两端加密同一样的字符串要结果相同进行验证加密是否正确,要以解密出来的东西是否相同为标准判断!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 | #import "RSAEncryptor.h" #import <Security/Security.h> @implementation RSAEncryptor static NSString *base64_encode_data( NSData *data){ data = [data base64EncodedDataWithOptions:0]; NSString *ret = [[ NSString alloc] initWithData:data encoding: NSUTF8StringEncoding ]; return ret; } static NSData *base64_decode( NSString *str){ NSData *data = [[ NSData alloc] initWithBase64EncodedString:str options: NSDataBase64DecodingIgnoreUnknownCharacters ]; return data; } #pragma mark - 使用'.der'公钥文件加密 //加密 + ( NSString *)encryptString:( NSString *)str publicKeyWithContentsOfFile:( NSString *)path{ if (!str || !path) return nil ; return [ self encryptString:str publicKeyRef:[ self getPublicKeyRefWithContentsOfFile:path]]; } //获取公钥 + (SecKeyRef)getPublicKeyRefWithContentsOfFile:( NSString *)filePath{ NSData *certData = [ NSData dataWithContentsOfFile:filePath]; if (!certData) { return nil ; } SecCertificateRef cert = SecCertificateCreateWithData( NULL , (CFDataRef)certData); SecKeyRef key = NULL ; SecTrustRef trust = NULL ; SecPolicyRef policy = NULL ; if (cert != NULL ) { policy = SecPolicyCreateBasicX509(); if (policy) { if (SecTrustCreateWithCertificates((CFTypeRef)cert, policy, &trust) == noErr) { SecTrustResultType result; if (SecTrustEvaluate(trust, &result) == noErr) { key = SecTrustCopyPublicKey(trust); } } } } if (policy) CFRelease(policy); if (trust) CFRelease(trust); if (cert) CFRelease(cert); return key; } + ( NSString *)encryptString:( NSString *)str publicKeyRef:(SecKeyRef)publicKeyRef{ if (![str dataUsingEncoding: NSUTF8StringEncoding ]){ return nil ; } if (!publicKeyRef){ return nil ; } NSData *data = [ self encryptData:[str dataUsingEncoding: NSUTF8StringEncoding ] withKeyRef:publicKeyRef]; NSString *ret = base64_encode_data(data); return ret; } #pragma mark - 使用'.12'私钥文件解密 //解密 + ( NSString *)decryptString:( NSString *)str privateKeyWithContentsOfFile:( NSString *)path password:( NSString *)password{ if (!str || !path) return nil ; if (!password) password = @ "" ; return [ self decryptString:str privateKeyRef:[ self getPrivateKeyRefWithContentsOfFile:path password:password]]; } //获取私钥 + (SecKeyRef)getPrivateKeyRefWithContentsOfFile:( NSString *)filePath password:( NSString *)password{ NSData *p12Data = [ NSData dataWithContentsOfFile:filePath]; if (!p12Data) { return nil ; } SecKeyRef privateKeyRef = NULL ; NSMutableDictionary * options = [[ NSMutableDictionary alloc] init]; [options setObject: password forKey:(__bridge id )kSecImportExportPassphrase]; CFArrayRef items = CFArrayCreate( NULL , 0, 0, NULL ); OSStatus securityError = SecPKCS12Import((__bridge CFDataRef) p12Data, (__bridge CFDictionaryRef)options, &items); if (securityError == noErr && CFArrayGetCount(items) > 0) { CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0); SecIdentityRef identityApp = (SecIdentityRef)CFDictionaryGetValue(identityDict, kSecImportItemIdentity); securityError = SecIdentityCopyPrivateKey(identityApp, &privateKeyRef); if (securityError != noErr) { privateKeyRef = NULL ; } } CFRelease(items); return privateKeyRef; } + ( NSString *)decryptString:( NSString *)str privateKeyRef:(SecKeyRef)privKeyRef{ NSData *data = [[ NSData alloc] initWithBase64EncodedString:str options: NSDataBase64DecodingIgnoreUnknownCharacters ]; if (!privKeyRef) { return nil ; } data = [ self decryptData:data withKeyRef:privKeyRef]; NSString *ret = [[ NSString alloc] initWithData:data encoding: NSUTF8StringEncoding ]; return ret; } #pragma mark - 使用公钥字符串加密 /* START: Encryption with RSA public key */ //使用公钥字符串加密 + ( NSString *)encryptString:( NSString *)str publicKey:( NSString *)pubKey{ NSData *data = [ self encryptData:[str dataUsingEncoding: NSUTF8StringEncoding ] publicKey:pubKey]; NSString *ret = base64_encode_data(data); return ret; } + ( NSData *)encryptData:( NSData *)data publicKey:( NSString *)pubKey{ if (!data || !pubKey){ return nil ; } SecKeyRef keyRef = [ self addPublicKey:pubKey]; if (!keyRef){ return nil ; } return [ self encryptData:data withKeyRef:keyRef]; } + (SecKeyRef)addPublicKey:( NSString *)key{ NSRange spos = [key rangeOfString:@ "-----BEGIN PUBLIC KEY-----" ]; NSRange epos = [key rangeOfString:@ "-----END PUBLIC KEY-----" ]; if (spos.location != NSNotFound && epos.location != NSNotFound ){ NSUInteger s = spos.location + spos.length; NSUInteger e = epos.location; NSRange range = NSMakeRange (s, e-s); key = [key substringWithRange:range]; } key = [key stringByReplacingOccurrencesOfString:@ "\r" withString:@ "" ]; key = [key stringByReplacingOccurrencesOfString:@ "\n" withString:@ "" ]; key = [key stringByReplacingOccurrencesOfString:@ "\t" withString:@ "" ]; key = [key stringByReplacingOccurrencesOfString:@ " " withString:@ "" ]; // This will be base64 encoded, decode it. NSData *data = base64_decode(key); data = [ self stripPublicKeyHeader:data]; if (!data){ return nil ; } //a tag to read/write keychain storage NSString *tag = @ "RSAUtil_PubKey" ; NSData *d_tag = [ NSData dataWithBytes:[tag UTF8String] length:[tag length]]; // Delete any old lingering key with the same tag NSMutableDictionary *publicKey = [[ NSMutableDictionary alloc] init]; [publicKey setObject:(__bridge id ) kSecClassKey forKey:(__bridge id )kSecClass]; [publicKey setObject:(__bridge id ) kSecAttrKeyTypeRSA forKey:(__bridge id )kSecAttrKeyType]; [publicKey setObject:d_tag forKey:(__bridge id )kSecAttrApplicationTag]; SecItemDelete((__bridge CFDictionaryRef)publicKey); // Add persistent version of the key to system keychain [publicKey setObject:data forKey:(__bridge id )kSecValueData]; [publicKey setObject:(__bridge id ) kSecAttrKeyClassPublic forKey:(__bridge id ) kSecAttrKeyClass]; [publicKey setObject:[ NSNumber numberWithBool: YES ] forKey:(__bridge id ) kSecReturnPersistentRef]; CFTypeRef persistKey = nil ; OSStatus status = SecItemAdd((__bridge CFDictionaryRef)publicKey, &persistKey); if (persistKey != nil ){ CFRelease(persistKey); } if ((status != noErr) && (status != errSecDuplicateItem)) { return nil ; } [publicKey removeObjectForKey:(__bridge id )kSecValueData]; [publicKey removeObjectForKey:(__bridge id )kSecReturnPersistentRef]; [publicKey setObject:[ NSNumber numberWithBool: YES ] forKey:(__bridge id )kSecReturnRef]; [publicKey setObject:(__bridge id ) kSecAttrKeyTypeRSA forKey:(__bridge id )kSecAttrKeyType]; // Now fetch the SecKeyRef version of the key SecKeyRef keyRef = nil ; status = SecItemCopyMatching((__bridge CFDictionaryRef)publicKey, (CFTypeRef *)&keyRef); if (status != noErr){ return nil ; } return keyRef; } + ( NSData *)stripPublicKeyHeader:( NSData *)d_key{ // Skip ASN.1 public key header if (d_key == nil ) return ( nil ); unsigned long len = [d_key length]; if (!len) return ( nil ); unsigned char *c_key = (unsigned char *)[d_key bytes]; unsigned int idx = 0; if (c_key[idx++] != 0x30) return ( nil ); if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1; else idx++; // PKCS #1 rsaEncryption szOID_RSA_RSA static unsigned char seqiod[] = { 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00 }; if (memcmp(&c_key[idx], seqiod, 15)) return ( nil ); idx += 15; if (c_key[idx++] != 0x03) return ( nil ); if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1; else idx++; if (c_key[idx++] != '\0' ) return ( nil ); // Now make a new NSData from this buffer return ([ NSData dataWithBytes:&c_key[idx] length:len - idx]); } + ( NSData *)encryptData:( NSData *)data withKeyRef:(SecKeyRef) keyRef{ const uint8_t *srcbuf = ( const uint8_t *)[data bytes]; size_t srclen = (size_t)data.length; size_t block_size = SecKeyGetBlockSize(keyRef) * sizeof (uint8_t); void *outbuf = malloc(block_size); size_t src_block_size = block_size - 11; NSMutableData *ret = [[ NSMutableData alloc] init]; for ( int idx=0; idx<srclen; idx+=src_block_size){ //NSLog(@"%d/%d block_size: %d", idx, (int)srclen, (int)block_size); size_t data_len = srclen - idx; if (data_len > src_block_size){ data_len = src_block_size; } size_t outlen = block_size; OSStatus status = noErr; status = SecKeyEncrypt(keyRef, kSecPaddingPKCS1, srcbuf + idx, data_len, outbuf, &outlen ); if (status != 0) { NSLog (@ "SecKeyEncrypt fail. Error Code: %d" , status); ret = nil ; break ; } else { [ret appendBytes:outbuf length:outlen]; } } free(outbuf); CFRelease(keyRef); return ret; } /* END: Encryption with RSA public key */ <br> #pragma mark - 使用私钥字符串解密 /* START: Decryption with RSA private key */ //使用私钥字符串解密 + ( NSString *)decryptString:( NSString *)str privateKey:( NSString *)privKey{ if (!str) return nil ; NSData *data = [[ NSData alloc] initWithBase64EncodedString:str options: NSDataBase64DecodingIgnoreUnknownCharacters ]; data = [ self decryptData:data privateKey:privKey]; NSString *ret = [[ NSString alloc] initWithData:data encoding: NSUTF8StringEncoding ]; return ret; } + ( NSData *)decryptData:( NSData *)data privateKey:( NSString *)privKey{ if (!data || !privKey){ return nil ; } SecKeyRef keyRef = [ self addPrivateKey:privKey]; if (!keyRef){ return nil ; } return [ self decryptData:data withKeyRef:keyRef]; } + (SecKeyRef)addPrivateKey:( NSString *)key{ NSRange spos = [key rangeOfString:@ "-----BEGIN RSA PRIVATE KEY-----" ]; NSRange epos = [key rangeOfString:@ "-----END RSA PRIVATE KEY-----" ]; if (spos.location != NSNotFound && epos.location != NSNotFound ){ NSUInteger s = spos.location + spos.length; NSUInteger e = epos.location; NSRange range = NSMakeRange (s, e-s); key = [key substringWithRange:range]; } key = [key stringByReplacingOccurrencesOfString:@ "\r" withString:@ "" ]; key = [key stringByReplacingOccurrencesOfString:@ "\n" withString:@ "" ]; key = [key stringByReplacingOccurrencesOfString:@ "\t" withString:@ "" ]; key = [key stringByReplacingOccurrencesOfString:@ " " withString:@ "" ]; // This will be base64 encoded, decode it. NSData *data = base64_decode(key); data = [ self stripPrivateKeyHeader:data]; if (!data){ return nil ; } //a tag to read/write keychain storage NSString *tag = @ "RSAUtil_PrivKey" ; NSData *d_tag = [ NSData dataWithBytes:[tag UTF8String] length:[tag length]]; // Delete any old lingering key with the same tag NSMutableDictionary *privateKey = [[ NSMutableDictionary alloc] init]; [privateKey setObject:(__bridge id ) kSecClassKey forKey:(__bridge id )kSecClass]; [privateKey setObject:(__bridge id ) kSecAttrKeyTypeRSA forKey:(__bridge id )kSecAttrKeyType]; [privateKey setObject:d_tag forKey:(__bridge id )kSecAttrApplicationTag]; SecItemDelete((__bridge CFDictionaryRef)privateKey); // Add persistent version of the key to system keychain [privateKey setObject:data forKey:(__bridge id )kSecValueData]; [privateKey setObject:(__bridge id ) kSecAttrKeyClassPrivate forKey:(__bridge id ) kSecAttrKeyClass]; [privateKey setObject:[ NSNumber numberWithBool: YES ] forKey:(__bridge id ) kSecReturnPersistentRef]; CFTypeRef persistKey = nil ; OSStatus status = SecItemAdd((__bridge CFDictionaryRef)privateKey, &persistKey); if (persistKey != nil ){ CFRelease(persistKey); } if ((status != noErr) && (status != errSecDuplicateItem)) { return nil ; } [privateKey removeObjectForKey:(__bridge id )kSecValueData]; [privateKey removeObjectForKey:(__bridge id )kSecReturnPersistentRef]; [privateKey setObject:[ NSNumber numberWithBool: YES ] forKey:(__bridge id )kSecReturnRef]; [privateKey setObject:(__bridge id ) kSecAttrKeyTypeRSA forKey:(__bridge id )kSecAttrKeyType]; // Now fetch the SecKeyRef version of the key SecKeyRef keyRef = nil ; status = SecItemCopyMatching((__bridge CFDictionaryRef)privateKey, (CFTypeRef *)&keyRef); if (status != noErr){ return nil ; } return keyRef; } + ( NSData *)stripPrivateKeyHeader:( NSData *)d_key{ // Skip ASN.1 private key header if (d_key == nil ) return ( nil ); unsigned long len = [d_key length]; if (!len) return ( nil ); unsigned char *c_key = (unsigned char *)[d_key bytes]; unsigned int idx = 22; //magic byte at offset 22 if (0x04 != c_key[idx++]) return nil ; //calculate length of the key unsigned int c_len = c_key[idx++]; int det = c_len & 0x80; if (!det) { c_len = c_len & 0x7f; } else { int byteCount = c_len & 0x7f; if (byteCount + idx > len) { //rsa length field longer than buffer return nil ; } unsigned int accum = 0; unsigned char *ptr = &c_key[idx]; idx += byteCount; while (byteCount) { accum = (accum << 8) + *ptr; ptr++; byteCount--; } c_len = accum; } // Now make a new NSData from this buffer return [d_key subdataWithRange: NSMakeRange (idx, c_len)]; } + ( NSData *)decryptData:( NSData *)data withKeyRef:(SecKeyRef) keyRef{ const uint8_t *srcbuf = ( const uint8_t *)[data bytes]; size_t srclen = (size_t)data.length; size_t block_size = SecKeyGetBlockSize(keyRef) * sizeof (uint8_t); UInt8 *outbuf = malloc(block_size); size_t src_block_size = block_size; NSMutableData *ret = [[ NSMutableData alloc] init]; for ( int idx=0; idx<srclen; idx+=src_block_size){ //NSLog(@"%d/%d block_size: %d", idx, (int)srclen, (int)block_size); size_t data_len = srclen - idx; if (data_len > src_block_size){ data_len = src_block_size; } size_t outlen = block_size; OSStatus status = noErr; status = SecKeyDecrypt(keyRef, kSecPaddingNone, srcbuf + idx, data_len, outbuf, &outlen ); if (status != 0) { NSLog (@ "SecKeyEncrypt fail. Error Code: %d" , status); ret = nil ; break ; } else { //the actual decrypted data is in the middle, locate it! int idxFirstZero = -1; int idxNextZero = ( int )outlen; for ( int i = 0; i < outlen; i++ ) { if ( outbuf[i] == 0 ) { if ( idxFirstZero < 0 ) { idxFirstZero = i; } else { idxNextZero = i; break ; } } } [ret appendBytes:&outbuf[idxFirstZero+1] length:idxNextZero-idxFirstZero-1]; } } free(outbuf); CFRelease(keyRef); return ret; } /* END: Decryption with RSA private key */ @end |
注意: 在我们使用RSA的p12文件解密的时候 也就是使用下面这个方法的时候:
+ (
NSString
*)decryptString:(
NSString
*)str privateKeyWithContentsOfFile:(
NSString
*)path password:(
NSString
*)password
使用到的 password 的这个参数就是我们给 p12文件设置的密码。这也是为什么前面我们说的你的记住这个密码的原因,不然你只能重新生成了。当然服务端解密的时候是不需要的。
path 这个参数就是你的p12文件在你本地的路径,这个就自己写了。
四:AES呢
首先的说说AES我们需要注意的几个点:
1、加密位数 128还是256的这个得几个端统一不能说你用256的服务端解的时候用128的。
2、IV 初始向量 这个也得统一,一般128的加密位数使用16位的初始向量
3、具体的AES加密代码的注释我在前面的博客中有写,它里面参数的含义是什么都有说明,这里就简单的看一下128加密代码,要是想看这个加密方法的具体说明,找一下以前的博客。
4、string的加密解密还是归结到data的加密解密了,先看data的加密解密:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | #import "NSData+AES.h" static NSString * const AES_IV = @ "自己定义" ; @implementation NSData (AES) - ( NSData *)aes128_encrypt:( NSString *)key //加密 { // kCCKeySizeAES256是加密位数 /* enum { kCCKeySizeAES128 = 16, kCCKeySizeAES192 = 24, kCCKeySizeAES256 = 32, kCCKeySizeDES = 8, kCCKeySize3DES = 24, kCCKeySizeMinCAST = 5, kCCKeySizeMaxCAST = 16, kCCKeySizeMinRC4 = 1, kCCKeySizeMaxRC4 = 512, kCCKeySizeMinRC2 = 1, kCCKeySizeMaxRC2 = 128, kCCKeySizeMinBlowfish = 8, kCCKeySizeMaxBlowfish = 56, }; */ char keyPtr[kCCKeySizeAES128+1]; bzero(keyPtr, sizeof (keyPtr)); [key getCString:keyPtr maxLength: sizeof (keyPtr) encoding: NSUTF8StringEncoding ]; NSUInteger dataLength = [ self length]; size_t bufferSize = dataLength + kCCBlockSizeAES128; void * buffer = malloc(bufferSize); size_t numBytesEncrypted = 0; // CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, keyPtr, kCCBlockSizeAES128, [AES_IV UTF8String], [ self bytes], dataLength, buffer, bufferSize, &numBytesEncrypted); if (cryptStatus == kCCSuccess) { return [ NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted]; } free(buffer); return nil ; } - ( NSData *)aes128_decrypt:( NSString *)key //解密 { char keyPtr[kCCKeySizeAES128+1]; bzero(keyPtr, sizeof (keyPtr)); [key getCString:keyPtr maxLength: sizeof (keyPtr) encoding: NSUTF8StringEncoding ]; NSUInteger dataLength = [ self length]; size_t bufferSize = dataLength + kCCBlockSizeAES128; void *buffer = malloc(bufferSize); size_t numBytesDecrypted = 0; CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding , keyPtr, kCCBlockSizeAES128, [AES_IV UTF8String], [ self bytes], dataLength, buffer, bufferSize, &numBytesDecrypted); if (cryptStatus == kCCSuccess) { return [ NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted]; } free(buffer); return nil ; } |
5、String的加密解密 128 位的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | // 利用Key加密字符串 -( NSString *) aes_encrypt:( NSString *)key{ const char *cstr = [ self cStringUsingEncoding: NSUTF8StringEncoding ]; NSData *data = [ NSData dataWithBytes:cstr length: self .length]; //对数据进行加密 NSData *result = [data aes128_encrypt:key]; //转换为2进制字符串 if (result && result.length > 0) { Byte *datas = (Byte*)[result bytes]; NSMutableString *output = [ NSMutableString stringWithCapacity:result.length * 2]; for ( int i = 0; i < result.length; i++){ [output appendFormat:@ "%02x" , datas[i]]; } return output; } return nil ; } //利用Key解密字符串 -( NSString *) aes_decrypt:( NSString *)key{ //转换为2进制Data NSMutableData *data = [ NSMutableData dataWithCapacity: self .length / 2]; unsigned char whole_byte; char byte_chars[3] = { '\0' , '\0' , '\0' }; int i; for (i=0; i < [ self length] / 2; i++) { byte_chars[0] = [ self characterAtIndex:i*2]; byte_chars[1] = [ self characterAtIndex:i*2+1]; whole_byte = strtol(byte_chars, NULL , 16); [data appendBytes:&whole_byte length:1]; } //对数据进行解密 NSData * result = [data aes128_decrypt:key]; if (result && result.length > 0) { return [[ NSString alloc] initWithData:result encoding: NSUTF8StringEncoding ]; } return nil ; } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
2017-06-27 iOS 转场动画探究(二)