iOS開(kāi)發(fā)中,與PHP后臺(tái)進(jìn)行加解密通常會(huì)用到RSA算法。RSA算法是一種非對(duì)稱加密算法,采用公鑰加密、私鑰解密的方式進(jìn)行數(shù)據(jù)加解密,安全性高。iOS與PHP后臺(tái)之間進(jìn)行RSA加解密的方式有兩種,一種是iOS通過(guò)PHP提供的API進(jìn)行加解密,一種是iOS自行生成RSA公鑰私鑰對(duì)進(jìn)行加解密。以下將介紹這兩種方式。
使用PHP提供的API進(jìn)行RSA加解密
PHP中提供了openssl擴(kuò)展來(lái)支持RSA加解密。在PHP后臺(tái)中調(diào)用openssl函數(shù)庫(kù)進(jìn)行RSA加解密,iOS端調(diào)用后臺(tái)提供的API進(jìn)行數(shù)據(jù)加解密。
// PHP代碼 // 生成RSA公鑰私鑰對(duì) $config = array( "digest_alg" =>"sha512", "private_key_bits" =>2048, "private_key_type" =>OPENSSL_KEYTYPE_RSA, ); $res = openssl_pkey_new($config); openssl_pkey_export($res, $privKey); $pubKey = openssl_pkey_get_details($res); $pubKey = $pubKey["key"]; // 加密數(shù)據(jù) $encrypted = ""; openssl_public_encrypt($data, $encrypted, $pubKey); echo base64_encode($encrypted); // 解密數(shù)據(jù) $decrypted = ""; openssl_private_decrypt(base64_decode($encrypted), $decrypted, $privKey); echo $decrypted;
iOS端調(diào)用后臺(tái)提供的API進(jìn)行RSA數(shù)據(jù)加解密:
// iOS代碼(Swift) // 加密數(shù)據(jù) let pubKeyDer = Data(base64Encoded: pubKey)! let pubKey = try! RSAKey.init(publicKeyDER: pubKeyDer) let encryptedData = try! pubKey.encrypt(data) // 解密數(shù)據(jù) let privKeyDer = Data(base64Encoded: privKey)! let privKey = try! RSAKey.init(privateKeyDER: privKeyDer) let decryptedData = try! privKey.decrypt(encryptedData) let decryptedString = String(bytes: decryptedData, encoding: .utf8)
iOS自行生成RSA公鑰私鑰對(duì)進(jìn)行加解密
iOS可以通過(guò)Security框架來(lái)生成RSA公鑰私鑰對(duì),在與PHP后臺(tái)進(jìn)行通信時(shí),將公鑰傳輸給PHP后臺(tái),PHP后臺(tái)用公鑰進(jìn)行加密,iOS端用私鑰進(jìn)行解密。
// iOS代碼(Objective-C) // 生成RSA公鑰私鑰對(duì) - (void)generateKeyPair { NSMutableDictionary * privateAttributes = [[NSMutableDictionary alloc] init]; NSMutableDictionary * publicAttributes = [[NSMutableDictionary alloc] init]; NSMutableDictionary * keyPairAttrs = [[NSMutableDictionary alloc] init]; NSData * publicTag = [@"com.company.publickey" dataUsingEncoding:NSUTF8StringEncoding]; NSData * privateTag = [@"com.company.privatekey" dataUsingEncoding:NSUTF8StringEncoding]; SecKeyRef publicKey = NULL; SecKeyRef privateKey = NULL; [publicAttributes setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType]; [privateAttributes setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType]; [publicAttributes setObject:publicTag forKey:(__bridge id)kSecAttrApplicationTag]; [privateAttributes setObject:privateTag forKey:(__bridge id)kSecAttrApplicationTag]; [keyPairAttrs setObject:[NSNumber numberWithUnsignedInt:2048] forKey:(__bridge id)kSecAttrKeySizeInBits]; [keyPairAttrs setObject:publicAttributes forKey:(__bridge id)kSecPublicKeyAttrs]; [keyPairAttrs setObject:privateAttributes forKey:(__bridge id)kSecPrivateKeyAttrs]; OSStatus status = SecKeyGeneratePair((__bridge CFDictionaryRef)keyPairAttrs, &publicKey, &privateKey); if (status != noErr) { NSLog(@"SecKeyGeneratePair failed"); return; } [self saveKey:publicKey tag:@"com.company.publickey"]; [self saveKey:privateKey tag:@"com.company.privatekey"]; } // 從鑰匙串中獲取私鑰 - (SecKeyRef)getPrivateKeyWithTag:(NSString *)tag { OSStatus status = noErr; SecKeyRef privateKey = NULL; NSData * peerTag = [tag dataUsingEncoding:NSUTF8StringEncoding]; NSDictionary * privateKeyAttr = @{ (__bridge id)kSecAttrKeyType : (__bridge id)kSecAttrKeyTypeRSA, (__bridge id)kSecAttrApplicationTag : peerTag, (__bridge id)kSecReturnRef : (__bridge id)kCFBooleanTrue }; status = SecItemCopyMatching((__bridge CFDictionaryRef)privateKeyAttr, (CFTypeRef *)&privateKey); if (status != noErr || privateKey == NULL) { NSLog(@"getPrivateKeyWithTag failed"); return NULL; } return privateKey; } // 使用私鑰解密數(shù)據(jù) - (NSData *)decryptWithPrivateKey:(NSData *)cipherText { SecKeyRef privateKey = [self getPrivateKeyWithTag:@"com.company.privatekey"]; size_t length = SecKeyGetBlockSize(privateKey) - 11; // 解密時(shí)需要減去11個(gè)字節(jié) NSMutableData * decryptedData = [NSMutableData data]; int idx = 0; while (idx< cipherText.length) { NSInteger chunkSize = MIN(length, cipherText.length - idx); NSData * chunkData = [cipherText subdataWithRange:NSMakeRange(idx, chunkSize)]; idx += chunkSize; size_t decryptedLength = length; uint8_t * decryptedBytes = malloc(decryptedLength); OSStatus status = SecKeyDecrypt(privateKey, kSecPaddingPKCS1, chunkData.bytes, chunkData.length, decryptedBytes, &decryptedLength); if (status != noErr) { free(decryptedBytes); return nil; } [decryptedData appendBytes:decryptedBytes length:decryptedLength]; free(decryptedBytes); } return decryptedData; }
PHP后臺(tái)將數(shù)據(jù)用公鑰進(jìn)行加密,iOS端通過(guò)獲取私鑰進(jìn)行數(shù)據(jù)解密,如下:
// PHP代碼 // 將公鑰傳輸給iOS端 echo $pubKey; // 加密數(shù)據(jù) openssl_public_encrypt($data, $encrypted, $pubKey); echo base64_encode($encrypted); // iOS代碼 // 接收公鑰并保存 let pubKeyData = Data(base64Encoded: receivedPubKey)! let pubKeyRef = try! PublicKey(data: pubKeyData) // 解密數(shù)據(jù) let decryptedData = self.decryptWithPrivateKey(encryptedData) let decryptedString = String(data: decryptedData!, encoding: .utf8)
以上便是iOS與PHP后臺(tái)進(jìn)行RSA數(shù)據(jù)加解密的兩種方式,開(kāi)發(fā)者在根據(jù)具體實(shí)際情況選擇使用哪種方式。