ECC橢圓曲線、ECDSA簽名驗籤和ECIES加解密
ECC橢圓曲線詳解
前言
ECC英文全稱"Ellipse Curve Cryptography",與傳統的基於大質數因子分解困難性的加密方法不同,ECC通過橢圓曲線方程式的性質產生金鑰
ECC164位的金鑰產生一個安全級,相當於RSA 1024位金鑰提供的保密強度,而且計算量較小,處理速度更快,儲存空間和傳輸頻寬佔用較少。目前我國居民二代身份證正在使用 256 位的橢圓曲線密碼,虛擬貨幣比特幣也選擇ECC作為加密演算法。
加密
基於這個祕密值,用來對Alice和Bob之間的報文進行加密的實際方法是適應以前的,最初是在其他組中描述使用的離散對數密碼系統。這些系統包括:Diffie-Hellman—ECDH
MQV—ECMQV
ElGamal discrete log cryptosystem—ECElGamal
數字簽名演算法—ECDSA
對於ECC系統來說,完成執行系統所必須的群操作比同樣大小的因數分解系統或模整數離散對數系統要慢。不過,ECC系統的擁護者相信ECDLP問題比DLP或因數分解問題要難的多,並且因此使用ECC能用小的多的金鑰長度來提供同等的安全,在這方面來說它確實比例如RSA之類的更快。到目前為止已經公佈的結果趨於支援這個結論,不過一些專家表示懷疑。
ECC被廣泛認為是在給定金鑰長度的情況下,最強大的非對稱演算法,因此在對頻寬要求十分緊的連線中會十分有用。
優點
安全性高
有研究表示160位的橢圓金鑰與1024位的RSA金鑰安全性相同。
處理速度快
在私鑰的加密解密速度上,ecc演算法比RSA、DSA速度更快。
儲存空間佔用小。
頻寬要求低。
以上為ECC橢圓曲線演算法需要了解的基本知識,摘自強大的百科度娘。
iOS-ECC
關於ECC,蘋果支援以下演算法:
PKG:
curves P-224, P-256, P-384, P-521PKV:
curves P-224, P-256, P-384, P-521Signature Generation:
curves P-224, P-256, P-384, P-521using (SHA-224, SHA-256, SHA384, SHA512)Signature Verification:curves P-224, P-256, P-384, P-521using (SHA-1, SHA-224, SHA-256, SHA384, SHA512)
採用的都是NIST標準和規範。但是蘋果官方API僅為開發者提供了橢圓曲線P-256的256位EC金鑰。由於蘋果SEP硬體提供的保護機制,私鑰會直接以keychain的形式截留在SEP中,不能提取,也不能從外部匯入,只能通過引用使用。
ECDSA
橢圓曲線數字簽名演算法(ECDSA)是使用橢圓曲線密碼(ECC)對數字簽名演算法(DSA)的模擬,下面是關於ECDSA的API呼叫。
1、建立ECC橢圓曲線的keychain屬性,屬性設定具體可以根據自己需要,獲取ECC私鑰。
sacObject = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, // kSecAccessControlTouchIDAny | kSecAccessControlPrivateKeyUsage, &error); // Create parameters dictionary for key generation. NSDictionary *parameters = @{ (id)kSecAttrTokenID: (id)kSecAttrTokenIDSecureEnclave, (id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeySizeInBits: @256, (id)kSecAttrLabel: @"my-se-key", (id)kSecPrivateKeyAttrs: @{ (id)kSecAttrAccessControl: (__bridge_transfer id)sacObject, (id)kSecAttrIsPermanent: @YES, } };
NSError *gen_error = nil;
//根據引數生成私鑰
id privateKey = CFBridgingRelease(SecKeyCreateRandomKey((__bridge CFDictionaryRef)parameters, (void *)&gen_error));
2.使用私鑰提取公鑰,並用於簽名。
//根據keychain的屬性查詢ECC私鑰,並獲取私鑰引用。
NSDictionary *params = @{
(id)kSecClass: (id)kSecClassKey, (id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeySizeInBits: @256, (id)kSecAttrLabel: @"my-se-key", (id)kSecReturnRef: @YES, (id)kSecUseOperationPrompt: @"Authenticate to sign data" };SecKeyRef privateKey; OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)params, (CFTypeRef *)&privateKey);
3.簽名
NSError *error;
NSData *dataToSign = [@"我是簽名內容" dataUsingEncoding:NSUTF8StringEncoding];
NSData *signature = CFBridgingRelease(SecKeyCreateSignature(privateKey, kSecKeyAlgorithmECDSASignatureMessageX962SHA256, (CFDataRef)dataToSign, (void *)&error));
對於kSecKeyAlgorithmECDSASignatureMessageX962SHA256簽名演算法,官方還給了:SHA1、SHA224、SHA384、SHA512用於EC金鑰摘要。可以自己需求選擇簽名對應的摘要演算法。API的名字也很明確的給了這裡執行的標準規範為X9.62。
4.驗籤
//提取公鑰,進行驗籤,驗籤選擇的演算法必須與簽名時的演算法一致。
id publicKey = CFBridgingRelease(SecKeyCopyPublicKey((SecKeyRef)privateKey));
Boolean verified = SecKeyVerifySignature((SecKeyRef)publicKey, kSecKeyAlgorithmECDSASignatureMessageX962SHA256, (CFDataRef)dataToSign, (CFDataRef)signature, (void *)&error); if (verified == 1) { message = [NSString stringWithFormat:@"signature:%@ verified:%@ error:%@", signature, @"驗籤成功", error]; }else{ message = [NSString stringWithFormat:@"signature:%@ verified:%@ error:%@", signature, @"驗籤失敗", error]; }ECIES
校驗金鑰是否和演算法是否匹配,只有都符合條件了才能用於加密。
SecKeyAlgorithm algorithm = kSecKeyAlgorithmECIESEncryptionCofactorX963SHA256AESGCM;
BOOL canEncrypt = SecKeyIsAlgorithmSupported((SecKeyRef)publicKey, kSecKeyOperationTypeEncrypt, algorithm);加密 CFErrorRef error = NULL;
cipherText = (NSData*)CFBridgingRelease( // ARC takes ownership
SecKeyCreateEncryptedData(publicKey,
algorithm,
(__bridge CFDataRef)encryptionData,
&error));
encryptionData為要加密的資料,這裡提示一下:
As an additional check before encrypting, because asymmetric encryption restricts the length of the data that you can encrypt, verify that the data is short enough. For this particular algorithm, the plain text data must be 130 bytes smaller than the key’s block size, as reported by SecKeyGetBlockSize
. You therefore further condition the proceedings on a length test:
NSData* plainText = <
canEncrypt &= ([plainText length] < (SecKeyGetBlockSize(publicKey)-130));
官方API描述,明文資料要比金鑰塊小130個位元組。
解密
CFErrorRef error = NULL;
clearText = (NSData*)CFBridgingRelease( // ARC takes ownership
SecKeyCreateDecryptedData(private,
algorithm,
(__bridge CFDataRef)cipherText,
&error));
---------------------------------結束了,無話可說-------------------------------------