天天看點

iOS-加密算法

一、雜湊演算法(簽名算法/摘要)

雜湊演算法,又稱哈希函數,是一種單向加密算法。在資訊安全技術中,經常需要驗證消息的完整性,散列(Hash)函數提供了這一服務,它對不同長度的輸入消息,産生固定長度的輸出。因為其結果是不可逆的,既然是不可逆的,那麼當然不是用來加密的,而是簽名。

  • MD5

    不可逆:MD5是不可逆轉的。

    壓縮性:任意長度的資料,算出的MD5值長度都是固定的。

    容易計算:從原資料計算出MD5值很容易。

    抗修改性:對原資料進行任何改動,哪怕隻修改1個位元組,所得到的MD5值都有很大差別。

    強抗碰撞:已知原資料和其MD5值,想找到一個具有相同MD5值的資料是非常困難的。

    主要用于驗證,防止資訊被修。具體用途如:檔案校驗、數字簽名、鑒權協定。

-(NSString *)md5 {
    if (!self) return nil;
    
    const char *cStr = self.UTF8String;
    unsigned char result[CC_MD5_DIGEST_LENGTH];
    CC_MD5(cStr, (CC_LONG)strlen(cStr), result);
    
    NSMutableString *md5Str = [NSMutableString string];
    for (int i = 0; i < CC_MD5_DIGEST_LENGTH; ++i) {
        [md5Str appendFormat:@"%02x", result[i]];
    }
    return md5Str;
}
           
  • SHA

    是由NISTNSA設計為同DSA一起使用的,它對長度小于264的輸入,産生長度為160bit的散列值,是以抗窮舉(brute-force)性更好。

    SHA-1設計時基于和MD4相同原理,并且模仿了該算法。

    SHA-1是由美國标準技術局(NIST)頒布的國家标準,是一種應用最為廣泛的Hash函數算法,也是目前最先進的加密技術,被政府部門和私營業主用來處理敏感的資訊。

    SHA-1基于MD5,MD5又基于MD4。

- (NSString*) sha1
{
    const char *cstr = [self cStringUsingEncoding:NSUTF8StringEncoding];
    NSData *data = [NSData dataWithBytes:cstr length:self.length];
    //使用對應的CC_SHA1,CC_SHA256,CC_SHA384,CC_SHA512的長度分别是20,32,48,64
    uint8_t digest[CC_SHA1_DIGEST_LENGTH];
    //使用對應的CC_SHA256,CC_SHA384,CC_SHA512
    CC_SHA1(data.bytes, data.length, digest);
    
    NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
    
    for(int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++)
        [output appendFormat:@"%02x", digest[i]];
    
    return output;
}
           

二、對稱算法

對稱式加密就是加密和解密使用同一個密鑰。資訊接收雙方都需事先知道密匙和加解密算法且其密匙是相同的,之後便是對資料進行加解密了。對稱加密算法用來對敏感資料等資訊進行加密。

  • AES

    進階加密标準,目前美國國家安全局使用的,蘋果的鑰匙串通路采用的就AES加密。是現在公認的最安全的加密方式,是對稱密鑰加密中最流行的算法。

    主要應用在關鍵資料和檔案的的保密同時又需要解密的情形,其加密密鑰和解密密鑰相同,根據密鑰長度分為128、192和256三種級别,密鑰長度越大安全性也就越大,但性能也就越低,根據實際業務的安全要求來決定就好。通常情況,對一些關鍵資料進行加密的對象都是字元串,加密結果也以字元串進行儲存,是以在設計接口的時候參數和傳回值均為字元串。

//AES128位加密 base64編碼 注:kCCKeySizeAES128點進去可以更換256位加密
-(NSString *)aes128Encrypt:(NSString *)key
{
    char keyPtr[kCCKeySizeAES128+1];//
    memset(keyPtr, 0, sizeof(keyPtr));
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
    
    NSData* data = [self dataUsingEncoding:NSUTF8StringEncoding];
    NSUInteger dataLength = [data length];
    
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);
    size_t numBytesEncrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
                                          kCCAlgorithmAES128,
                                          kCCOptionPKCS7Padding|kCCOptionECBMode,
                                          keyPtr,
                                          kCCBlockSizeAES128,
                                          NULL,
                                          [data bytes],
                                          dataLength,
                                          buffer,
                                          bufferSize,
                                          &numBytesEncrypted);
    if (cryptStatus == kCCSuccess) {
        NSData *resultData = [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
        
        NSString *stringBase64 = [resultData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed]; // base64格式的字元串
        return stringBase64;
        
    }
    free(buffer);
    return nil;
}

//解密
-(NSString *)aes128Decrypt:(NSString *)key
{
    char keyPtr[kCCKeySizeAES128 + 1];
    memset(keyPtr, 0, sizeof(keyPtr));
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
    
    NSData *data = [[NSData alloc] initWithBase64EncodedString:self options:NSDataBase64DecodingIgnoreUnknownCharacters];//base64解碼
    
    NSUInteger dataLength = [data length];
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);
    
    size_t numBytesCrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
                                          kCCAlgorithmAES128,
                                          kCCOptionPKCS7Padding|kCCOptionECBMode,
                                          keyPtr,
                                          kCCBlockSizeAES128,
                                          NULL,
                                          [data bytes],
                                          dataLength,
                                          buffer,
                                          bufferSize,
                                          &numBytesCrypted);
    if (cryptStatus == kCCSuccess) {
        NSData *resultData = [NSData dataWithBytesNoCopy:buffer length:numBytesCrypted];
        
        return [[NSString alloc] initWithData:resultData encoding:NSUTF8StringEncoding];
    }
    free(buffer);
    return nil;
}
           
  • DES

    資料加密标準(現在用的比較少,因為它的加密強度不夠,能夠暴力破解)

- (NSString *) desEncrypt:(NSString *)key
{
    NSString *ciphertext = nil;
    const char *textBytes = [self UTF8String];
    NSUInteger dataLength = [self length];
  
    size_t bufferPtrSize = (dataLength + kCCBlockSizeDES) & ~(kCCBlockSizeDES - 1);
    unsigned char* buffer = (unsigned char *)malloc(bufferPtrSize);;
    memset(buffer, 0, bufferPtrSize);
    Byte iv[] = {1,2,3,4,5,6,7,8};
    size_t numBytesEncrypted = 0;
      
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, //  加密/解密
                                          kCCAlgorithmDES, //  加密根據哪個标準(des,3des,aes。。。。)
                                          kCCOptionPKCS7Padding, //  選項分組密碼算法(des:對每塊分組加一次密  3DES:對每塊分組加三個不同的密)
                                          [key UTF8String], //密鑰    加密和解密的密鑰必須一緻
                                          kCCKeySizeDES, //   DES 密鑰的大小(kCCKeySizeDES=8)
                                          iv, //  可選的初始矢量
                                          textBytes, dataLength,
                                          buffer, bufferPtrSize,
                                          &numBytesEncrypted);
    if (cryptStatus == kCCSuccess) {
        NSData *data = [NSData dataWithBytes:buffer length:(NSUInteger)numBytesEncrypted];
          
        ciphertext = [[NSString alloc] initWithData:[data base64EncodedDataWithOptions:0] encoding:NSUTF8StringEncoding];
    }
    free(buffer);
    return ciphertext;
}
  
//解密
- (NSString *) desDecrypt:(NSString*)key
{
    NSData* cipherData = [[NSData alloc] initWithBase64EncodedString:self options:0];
      
    NSUInteger dataLength = [self length];
    size_t bufferPtrSize = (dataLength + kCCBlockSizeDES) & ~(kCCBlockSizeDES - 1);
    unsigned char* buffer = (unsigned char *)malloc(bufferPtrSize);;
    memset(buffer, 0, bufferPtrSize);
      
    size_t numBytesDecrypted = 0;
    Byte iv[] = {1,2,3,4,5,6,7,8};
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
                                          kCCAlgorithmDES,
                                          kCCOptionPKCS7Padding,
                                          [key UTF8String],
                                          kCCKeySizeDES,
                                          iv,
                                          [cipherData bytes],
                                          [cipherData length],
                                          buffer,
                                          bufferPtrSize,
                                          &numBytesDecrypted);
    NSString* plainText = nil;
    if (cryptStatus == kCCSuccess) {
        NSData* data = [NSData dataWithBytes:buffer length:(NSUInteger)numBytesDecrypted];
        plainText = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    }
      
    free(buffer);
    return plainText;
}

           

三、非對稱算法

非對稱加密工作原理:

乙方生成一對密鑰(公鑰和私鑰)并将公鑰向其它方公開。

得到該公鑰的甲方使用該密鑰對機密資訊進行加密後再發送給乙方。

乙方再用自己儲存的另一把專用密鑰(私鑰)對加密後的資訊進行解密。乙方隻能用其專用密鑰(私鑰)解密由對應的公鑰加密後的資訊。

在傳輸過程中,即使攻擊者截獲了傳輸的密文,并得到了乙的公鑰,也無法破解密文,因為隻有乙的私鑰才能解密密文。同樣,如果乙要回複加密資訊給甲,那麼需要甲先公布甲的公鑰給乙用于加密,甲自己儲存甲的私鑰用于解密。

非對稱加密一般有兩種用途:

進行資料認證(鑒權)服務校驗,即對發送資料方是否是我們所期望的那個做驗證。私鑰加簽,公鑰驗簽。

對資料進行加密,公鑰加密,私鑰解密。由于非對稱加密算法的低效,是以各密碼機構主張對稱加密算法和非對稱加密算法結合,用對稱加密算法加密内容,用非對稱加密算法加密對稱算法的密鑰。在算法設計上,非對稱加密算法對待加密資料長度要求極為苛刻。比如,RSA算法要求待加密資料長度不得超過53個位元組。是以,非對稱加密主要用于交換對稱加密的秘密密鑰,而非資料内容上的加密。

  • RSA
  • 建立存儲密鑰檔案夾RSA
  • 在該檔案夾目錄下執行

    openssl

    指令
  • 生成私鑰:

    genrsa -out rsa_private_key.pem 1024

  • 将私鑰轉成PKCS8的格式,格式轉好後立刻複制

    pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt

  • 生成公鑰:

    rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem

    打開剛才的RSA檔案裡的

    rsa_public_key.pem

    擷取公鑰
  • 引入工具類 Objective-C-RSA,用于加密解密
NSString *pubkey = @"-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHNhQwlZs3zjic1m5rCwVZ9DEwPED9bgXvWRQVeRDA/iiZwbp1Z3xJI1ybu9IWzxBvmeh6Knilh36+MuRtMs3arVoIa3LgErPrYPDoMmEBfSloFiBh8MDmHzCM5pSU15qrVe5Ml4uTrazQhTuCi086Bj6Bmf70Bvoij+nC1WnLSwIDAQAB\n-----END PUBLIC KEY-----";
    NSString *privkey = @"-----BEGIN PRIVATE KEY-----\nMIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMc2FDCVmzfOOJzWbmsLBVn0MTA8QP1uBe9ZFBV5EMD+KJnBunVnfEkjXJu70hbPEG+Z6HoqeKWHfr4y5G0yzdqtWghrcuASs+tg8OgyYQF9KWgWIGHwwOYfMIzmlJTXmqtV7kyXi5OtrNCFO4KLTzoGPoGZ/vQG+iKP6cLVactLAgMBAAECgYBaH5QYusYjBA/GnJgNo0nDfV73dHrubGUQ+FrGsCOtPA6AKQ3C6ZNnvzC5X8pW+Ux1QMrU4fv83wSu5XVEFbTcyRNY58l2ZE9oHYh3CDr0kLSqBUpSx1MjCk6pHwrYeIKVQtyKZpNjwc6o8Iop4Vz0f5YLxSrt58tx/JH0Ndlr8QJBAPrho7I3tbcfKjL9k+61+A5Y5uzOfjwuOJynjoEeWLv1JLjT4uU2F1hlrhE7RpNWgRWV9zAoUIjK7kOWicdf3fkCQQDLRpCTh8SWKITwKHXJGEw49/l7RjKtn38ju4SuLkEfGZCd9+P1RO5FNuDWxLbJrPLR8yxHo+2uggJ4Gg6D25RjAkEAtC8sn4oNc7jpWPfwsGh3AO7u47MmzNgxhql82tVNy6i0OB7N/euMdsuIag3VkWp2iWdMwoSh2q1M1LQgvlXnGQJAKHSTw3jKzCOmSXGT94CpctEPStRus5VBpWflgRDdjwX0fSvfp2mfjhDc8IFX641LCjO+RUe/vvJK8YImD2H9BwJANxMZFA135dBXNZ/lKPZ/5p2bBfeJ7M9qnDJJpsASsGKrwbSCQUl1Qcq1oUVqvN0Z+syerVPtTztyMqNkLuwp5g==\n-----END PRIVATE KEY-----";

    NSString *originString = @"hello world!";
    
    NSLog(@"Original string(%d): %@", (int)originString.length, originString);
    
    // 公鑰加密
    NSString *encWithPubKey = [RSA encryptString:originString publicKey:pubkey];
    NSLog(@"Enctypted with public key: %@", encWithPubKey);
    // 私鑰解密
    NSString *decWithPrivKey = [RSA decryptString:encWithPubKey privateKey:privkey];
    NSLog(@"Decrypted with private key: %@", decWithPrivKey);
    
    // 私鑰加密
    NSString *encWithPrivKey = [RSA encryptString:originString privateKey:privkey];
    NSLog(@"Enctypted with private key: %@", encWithPrivKey);

    // 公鑰解密
    NSString *decWithPublicKey = [RSA decryptString:encWithPrivKey publicKey:pubkey];
    NSLog(@"Decrypted with public key: %@", decWithPublicKey);
    
列印結果
2020-09-05 10:56:51.829078+0800 ModuleProject[8630:93898] Original string: hello world!
2020-09-05 10:56:51.849902+0800 ModuleProject[8630:93898] Enctypted with public key: msJnCtTPe3KCvsg4psupRx/8gtyIABBLgkEqb46wvROnTIl3NcaGE0GOR8hQ5mgUPDd+2RrnNilB0d+/C+lQoOiu1zir33sezSS+HEygt0LQhWbbn4ZkD46Z8QhQJEYHnS8WERLUHOen31BEaWy+eMRCcAQ41zKlKpfKHx0rDtI=
2020-09-05 10:56:51.861117+0800 ModuleProject[8630:93898] Decrypted with private key: hello world!
2020-09-05 10:56:51.955834+0800 ModuleProject[8630:93898] Enctypted with private key: f7RidCBDRJ7DRKiIP3IhpP8Ob7jIzRc+7aarLOVmj4haRLmvI379rOxKtwRxbSzQV63vj3MIzUIuvpfF2c16osb1Is16PaxIj70ffZKBRzRx60OCy0DB5ZZGzE/GFVOdEkvTTXbGydfysxohUWZkB1VZmMZrNw1wTtkSK9bBVdM=
2020-09-05 10:56:51.984258+0800 ModuleProject[8630:93898] Decrypted with public key: hello world!