ForgetSou | Blog

❤ 武统台湾 刻不容缓 ❤

0%

iOS开发-AES/ECB/PKCS5Padding加解密(OC)

一. 简述

1. 加解密方式有很多,iOS常用的加密方式有:

  • 哈希算法: MD5、SHA
  • 对称加密算法: DES、3DES、AES
  • 非对称加密算法: RSA

本文主要讲述AES/ECB/PKCS5Padding加解密方式

二. 示例

1. 加密

#define k_aesECBKey                         @"AAAAA"// AAAAA只是示例,换成自己喜欢的字符串
// 加密
+ (NSString *)encryptText:(NSString *)text {
CCCryptorStatus status = kCCSuccess;
NSData *data = [text dataUsingEncoding:NSUTF8StringEncoding];
NSData *result = [data dataEncryptedUsingAlgorithm:kCCAlgorithmAES128
key:k_aesECBKey
initializationVector:nil
options:(kCCOptionPKCS7Padding|kCCOptionECBMode)
error:&status];
if (status != kCCSuccess) {
return @"";
}
return [self convertDataToHexStr:result];
}
/**
将十六进制data转为十六进制字符串

@param data 十六进制data
@return 十六进制字符串
*/
+ (NSString *)convertDataToHexStr:(NSData *)data {
if (!data || [data length] == 0) {
return @"";
}
NSMutableString *string = [[NSMutableString alloc] initWithCapacity:[data length]];

[data enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) {
unsigned char *dataBytes = (unsigned char*)bytes;
for (NSInteger i = 0; i < byteRange.length; i++) {
NSString *hexStr = [NSString stringWithFormat:@"%x", (dataBytes[i]) & 0xff];
if ([hexStr length] == 2) {
[string appendString:hexStr];
} else {
[string appendFormat:@"0%@", hexStr];
}
}
}];
return string;
}

2. 解密

// 解密
+ (NSString *)decryptHexStr:(NSString *)hexStr {
NSData *data = [self convertHexStrToData:hexStr];
CCCryptorStatus status = kCCSuccess;
NSData* result = [data decryptedDataUsingAlgorithm:kCCAlgorithmAES128
key:k_aesECBKey
initializationVector:nil // ECB解密不会用到iv
options:(kCCOptionPKCS7Padding|kCCOptionECBMode)
error:&status];
if (status != kCCSuccess) {
return @"";
}
return [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
}

+ (NSData *)convertHexStrToData:(NSString *)str {
if (!str || [str length] == 0) {
return nil;
}

NSMutableData *hexData = [[NSMutableData alloc] initWithCapacity:8];

NSRange range;

if ([str length] % 2 == 0) {
range = NSMakeRange(0, 2);

} else {
range = NSMakeRange(0, 1);
}

for (NSInteger i = range.location; i < [str length]; i+= 2){
unsigned int anInt;
NSString*hexCharStr= [str substringWithRange:range];

NSScanner*scanner= [[NSScanner alloc] initWithString:hexCharStr];

[scanner scanHexInt:&anInt];

NSData *entity= [[NSData alloc] initWithBytes:&anInt length:1];

[hexData appendData:entity];

range.location+= range.length;

range.length= 2;
}

return hexData;
}

⚠️ NSData+CommonCrypto.h


#import <Foundation/NSData.h>
#import <Foundation/NSError.h>
#import <CommonCrypto/CommonCryptor.h>
#import <CommonCrypto/CommonHMAC.h>

extern NSString * const kCommonCryptoErrorDomain;

@interface NSError (CommonCryptoErrorDomain)
+ (NSError *) errorWithCCCryptorStatus: (CCCryptorStatus) status;
@end

@interface NSData (CommonDigest)

- (NSData *) MD2Sum;
- (NSData *) MD4Sum;
- (NSData *) MD5Sum;

- (NSData *) SHA1Hash;
- (NSData *) SHA224Hash;
- (NSData *) SHA256Hash;
- (NSData *) SHA384Hash;
- (NSData *) SHA512Hash;

@end

@interface NSData (CommonCryptor)

- (NSData *) AES256EncryptedDataUsingKey: (id) key error: (NSError **) error;
- (NSData *) decryptedAES256DataUsingKey: (id) key error: (NSError **) error;

- (NSData *) DESEncryptedDataUsingKey: (id) key error: (NSError **) error;
- (NSData *) decryptedDESDataUsingKey: (id) key error: (NSError **) error;

- (NSData *) CASTEncryptedDataUsingKey: (id) key error: (NSError **) error;
- (NSData *) decryptedCASTDataUsingKey: (id) key error: (NSError **) error;

@end

@interface NSData (LowLevelCommonCryptor)

- (NSData *) dataEncryptedUsingAlgorithm: (CCAlgorithm) algorithm
key: (id) key // data or string
error: (CCCryptorStatus *) error;
- (NSData *) dataEncryptedUsingAlgorithm: (CCAlgorithm) algorithm
key: (id) key // data or string
options: (CCOptions) options
error: (CCCryptorStatus *) error;
- (NSData *) dataEncryptedUsingAlgorithm: (CCAlgorithm) algorithm
key: (id) key // data or string
initializationVector: (id) iv // data or string
options: (CCOptions) options
error: (CCCryptorStatus *) error;

- (NSData *) decryptedDataUsingAlgorithm: (CCAlgorithm) algorithm
key: (id) key // data or string
error: (CCCryptorStatus *) error;
- (NSData *) decryptedDataUsingAlgorithm: (CCAlgorithm) algorithm
key: (id) key // data or string
options: (CCOptions) options
error: (CCCryptorStatus *) error;
- (NSData *) decryptedDataUsingAlgorithm: (CCAlgorithm) algorithm
key: (id) key // data or string
initializationVector: (id) iv // data or string
options: (CCOptions) options
error: (CCCryptorStatus *) error;

@end

@interface NSData (CommonHMAC)

- (NSData *) HMACWithAlgorithm: (CCHmacAlgorithm) algorithm;
- (NSData *) HMACWithAlgorithm: (CCHmacAlgorithm) algorithm key: (id) key;

@end

⚠️ NSData+CommonCrypto.m

#import <Foundation/Foundation.h>
#import "NSData+CommonCrypto.h"
#import <CommonCrypto/CommonDigest.h>
#import <CommonCrypto/CommonCryptor.h>
#import <CommonCrypto/CommonHMAC.h>

NSString * const kCommonCryptoErrorDomain = @"CommonCryptoErrorDomain";

@implementation NSError (CommonCryptoErrorDomain)

+ (NSError *) errorWithCCCryptorStatus: (CCCryptorStatus) status
{
NSString * description = nil, * reason = nil;

switch ( status )
{
case kCCSuccess:
description = NSLocalizedString(@"Success", @"Error description");
break;

case kCCParamError:
description = NSLocalizedString(@"Parameter Error", @"Error description");
reason = NSLocalizedString(@"Illegal parameter supplied to encryption/decryption algorithm", @"Error reason");
break;

case kCCBufferTooSmall:
description = NSLocalizedString(@"Buffer Too Small", @"Error description");
reason = NSLocalizedString(@"Insufficient buffer provided for specified operation", @"Error reason");
break;

case kCCMemoryFailure:
description = NSLocalizedString(@"Memory Failure", @"Error description");
reason = NSLocalizedString(@"Failed to allocate memory", @"Error reason");
break;

case kCCAlignmentError:
description = NSLocalizedString(@"Alignment Error", @"Error description");
reason = NSLocalizedString(@"Input size to encryption algorithm was not aligned correctly", @"Error reason");
break;

case kCCDecodeError:
description = NSLocalizedString(@"Decode Error", @"Error description");
reason = NSLocalizedString(@"Input data did not decode or decrypt correctly", @"Error reason");
break;

case kCCUnimplemented:
description = NSLocalizedString(@"Unimplemented Function", @"Error description");
reason = NSLocalizedString(@"Function not implemented for the current algorithm", @"Error reason");
break;

default:
description = NSLocalizedString(@"Unknown Error", @"Error description");
break;
}

NSMutableDictionary * userInfo = [[NSMutableDictionary alloc] init];
[userInfo setObject: description forKey: NSLocalizedDescriptionKey];

if ( reason != nil )
[userInfo setObject: reason forKey: NSLocalizedFailureReasonErrorKey];

NSError * result = [NSError errorWithDomain: kCommonCryptoErrorDomain code: status userInfo: userInfo];
#if !__has_feature(objc_arc)
[userInfo release];
#endif

return ( result );
}

@end

#pragma mark -

@implementation NSData (CommonDigest)

- (NSData *) MD2Sum
{
unsigned char hash[CC_MD2_DIGEST_LENGTH];
(void) CC_MD2( [self bytes], (CC_LONG)[self length], hash );
return ( [NSData dataWithBytes: hash length: CC_MD2_DIGEST_LENGTH] );
}

- (NSData *) MD4Sum
{
unsigned char hash[CC_MD4_DIGEST_LENGTH];
(void) CC_MD4( [self bytes], (CC_LONG)[self length], hash );
return ( [NSData dataWithBytes: hash length: CC_MD4_DIGEST_LENGTH] );
}

- (NSData *) MD5Sum
{
unsigned char hash[CC_MD5_DIGEST_LENGTH];
(void) CC_MD5( [self bytes], (CC_LONG)[self length], hash );
return ( [NSData dataWithBytes: hash length: CC_MD5_DIGEST_LENGTH] );
}

- (NSData *) SHA1Hash
{
unsigned char hash[CC_SHA1_DIGEST_LENGTH];
(void) CC_SHA1( [self bytes], (CC_LONG)[self length], hash );
return ( [NSData dataWithBytes: hash length: CC_SHA1_DIGEST_LENGTH] );
}

- (NSData *) SHA224Hash
{
unsigned char hash[CC_SHA224_DIGEST_LENGTH];
(void) CC_SHA224( [self bytes], (CC_LONG)[self length], hash );
return ( [NSData dataWithBytes: hash length: CC_SHA224_DIGEST_LENGTH] );
}

- (NSData *) SHA256Hash
{
unsigned char hash[CC_SHA256_DIGEST_LENGTH];
(void) CC_SHA256( [self bytes], (CC_LONG)[self length], hash );
return ( [NSData dataWithBytes: hash length: CC_SHA256_DIGEST_LENGTH] );
}

- (NSData *) SHA384Hash
{
unsigned char hash[CC_SHA384_DIGEST_LENGTH];
(void) CC_SHA384( [self bytes], (CC_LONG)[self length], hash );
return ( [NSData dataWithBytes: hash length: CC_SHA384_DIGEST_LENGTH] );
}

- (NSData *) SHA512Hash
{
unsigned char hash[CC_SHA512_DIGEST_LENGTH];
(void) CC_SHA512( [self bytes], (CC_LONG)[self length], hash );
return ( [NSData dataWithBytes: hash length: CC_SHA512_DIGEST_LENGTH] );
}

@end

@implementation NSData (CommonCryptor)

- (NSData *) AES256EncryptedDataUsingKey: (id) key error: (NSError **) error
{
CCCryptorStatus status = kCCSuccess;
NSData * result = [self dataEncryptedUsingAlgorithm: kCCAlgorithmAES128
key: key
options: kCCOptionPKCS7Padding
error: &status];

if ( result != nil )
return ( result );

if ( error != NULL )
*error = [NSError errorWithCCCryptorStatus: status];

return ( nil );
}

- (NSData *) decryptedAES256DataUsingKey: (id) key error: (NSError **) error
{
CCCryptorStatus status = kCCSuccess;
NSData * result = [self decryptedDataUsingAlgorithm: kCCAlgorithmAES128
key: key
options: kCCOptionPKCS7Padding
error: &status];

if ( result != nil )
return ( result );

if ( error != NULL )
*error = [NSError errorWithCCCryptorStatus: status];

return ( nil );
}

- (NSData *) DESEncryptedDataUsingKey: (id) key error: (NSError **) error
{
CCCryptorStatus status = kCCSuccess;
NSData * result = [self dataEncryptedUsingAlgorithm: kCCAlgorithmDES
key: key
options: kCCOptionPKCS7Padding
error: &status];

if ( result != nil )
return ( result );

if ( error != NULL )
*error = [NSError errorWithCCCryptorStatus: status];

return ( nil );
}

- (NSData *) decryptedDESDataUsingKey: (id) key error: (NSError **) error
{
CCCryptorStatus status = kCCSuccess;
NSData * result = [self decryptedDataUsingAlgorithm: kCCAlgorithmDES
key: key
options: kCCOptionPKCS7Padding
error: &status];

if ( result != nil )
return ( result );

if ( error != NULL )
*error = [NSError errorWithCCCryptorStatus: status];

return ( nil );
}

- (NSData *) CASTEncryptedDataUsingKey: (id) key error: (NSError **) error
{
CCCryptorStatus status = kCCSuccess;
NSData * result = [self dataEncryptedUsingAlgorithm: kCCAlgorithmCAST
key: key
options: kCCOptionPKCS7Padding
error: &status];

if ( result != nil )
return ( result );

if ( error != NULL )
*error = [NSError errorWithCCCryptorStatus: status];

return ( nil );
}

- (NSData *) decryptedCASTDataUsingKey: (id) key error: (NSError **) error
{
CCCryptorStatus status = kCCSuccess;
NSData * result = [self decryptedDataUsingAlgorithm: kCCAlgorithmCAST
key: key
options: kCCOptionPKCS7Padding
error: &status];

if ( result != nil )
return ( result );

if ( error != NULL )
*error = [NSError errorWithCCCryptorStatus: status];

return ( nil );
}

@end

static void FixKeyLengths( CCAlgorithm algorithm, NSMutableData * keyData, NSMutableData * ivData )
{
NSUInteger keyLength = [keyData length];
switch ( algorithm )
{
case kCCAlgorithmAES128:
{
if ( keyLength < 16 )
{
[keyData setLength: 16];
}
else if ( keyLength < 24 )
{
[keyData setLength: 24];
}
else
{
[keyData setLength: 32];
}

break;
}

case kCCAlgorithmDES:
{
[keyData setLength: 8];
break;
}

case kCCAlgorithm3DES:
{
[keyData setLength: 24];
break;
}

case kCCAlgorithmCAST:
{
if ( keyLength < 5 )
{
[keyData setLength: 5];
}
else if ( keyLength > 16 )
{
[keyData setLength: 16];
}

break;
}

case kCCAlgorithmRC4:
{
if ( keyLength > 512 )
[keyData setLength: 512];
break;
}

default:
break;
}

[ivData setLength: [keyData length]];
}

@implementation NSData (LowLevelCommonCryptor)

- (NSData *) _runCryptor: (CCCryptorRef) cryptor result: (CCCryptorStatus *) status
{
size_t bufsize = CCCryptorGetOutputLength( cryptor, (size_t)[self length], true );
void * buf = malloc( bufsize );
size_t bufused = 0;
size_t bytesTotal = 0;
*status = CCCryptorUpdate( cryptor, [self bytes], (size_t)[self length],
buf, bufsize, &bufused );
if ( *status != kCCSuccess )
{
free( buf );
return ( nil );
}

bytesTotal += bufused;

// From Brent Royal-Gordon (Twitter: architechies):
// Need to update buf ptr past used bytes when calling CCCryptorFinal()
*status = CCCryptorFinal( cryptor, buf + bufused, bufsize - bufused, &bufused );
if ( *status != kCCSuccess )
{
free( buf );
return ( nil );
}

bytesTotal += bufused;

return ( [NSData dataWithBytesNoCopy: buf length: bytesTotal] );
}

- (NSData *) dataEncryptedUsingAlgorithm: (CCAlgorithm) algorithm
key: (id) key
error: (CCCryptorStatus *) error
{
return ( [self dataEncryptedUsingAlgorithm: algorithm
key: key
initializationVector: nil
options: 0
error: error] );
}

- (NSData *) dataEncryptedUsingAlgorithm: (CCAlgorithm) algorithm
key: (id) key
options: (CCOptions) options
error: (CCCryptorStatus *) error
{
return ( [self dataEncryptedUsingAlgorithm: algorithm
key: key
initializationVector: nil
options: options
error: error] );
}

- (NSData *) dataEncryptedUsingAlgorithm: (CCAlgorithm) algorithm
key: (id) key
initializationVector: (id) iv
options: (CCOptions) options
error: (CCCryptorStatus *) error
{
CCCryptorRef cryptor = NULL;
CCCryptorStatus status = kCCSuccess;

NSParameterAssert([key isKindOfClass: [NSData class]] || [key isKindOfClass: [NSString class]]);
NSParameterAssert(iv == nil || [iv isKindOfClass: [NSData class]] || [iv isKindOfClass: [NSString class]]);

NSMutableData * keyData, * ivData;
if ( [key isKindOfClass: [NSData class]] )
keyData = (NSMutableData *) [key mutableCopy];
else
keyData = [[key dataUsingEncoding: NSUTF8StringEncoding] mutableCopy];

if ( [iv isKindOfClass: [NSString class]] )
ivData = [[iv dataUsingEncoding: NSUTF8StringEncoding] mutableCopy];
else
ivData = (NSMutableData *) [iv mutableCopy]; // data or nil

#if !__has_feature(objc_arc)
[keyData autorelease];
[ivData autorelease];
#endif
// ensure correct lengths for key and iv data, based on algorithms
FixKeyLengths( algorithm, keyData, ivData );

status = CCCryptorCreate( kCCEncrypt, algorithm, options,
[keyData bytes], [keyData length], [ivData bytes],
&cryptor );

if ( status != kCCSuccess )
{
if ( error != NULL )
*error = status;
return ( nil );
}

NSData * result = [self _runCryptor: cryptor result: &status];
if ( (result == nil) && (error != NULL) )
*error = status;

CCCryptorRelease( cryptor );

return ( result );
}

- (NSData *) decryptedDataUsingAlgorithm: (CCAlgorithm) algorithm
key: (id) key // data or string
error: (CCCryptorStatus *) error
{
return ( [self decryptedDataUsingAlgorithm: algorithm
key: key
initializationVector: nil
options: 0
error: error] );
}

- (NSData *) decryptedDataUsingAlgorithm: (CCAlgorithm) algorithm
key: (id) key // data or string
options: (CCOptions) options
error: (CCCryptorStatus *) error
{
return ( [self decryptedDataUsingAlgorithm: algorithm
key: key
initializationVector: nil
options: options
error: error] );
}

- (NSData *) decryptedDataUsingAlgorithm: (CCAlgorithm) algorithm
key: (id) key // data or string
initializationVector: (id) iv // data or string
options: (CCOptions) options
error: (CCCryptorStatus *) error
{
CCCryptorRef cryptor = NULL;
CCCryptorStatus status = kCCSuccess;

NSParameterAssert([key isKindOfClass: [NSData class]] || [key isKindOfClass: [NSString class]]);
NSParameterAssert(iv == nil || [iv isKindOfClass: [NSData class]] || [iv isKindOfClass: [NSString class]]);

NSMutableData * keyData, * ivData;
if ( [key isKindOfClass: [NSData class]] )
keyData = (NSMutableData *) [key mutableCopy];
else
keyData = [[key dataUsingEncoding: NSUTF8StringEncoding] mutableCopy];

if ( [iv isKindOfClass: [NSString class]] )
ivData = [[iv dataUsingEncoding: NSUTF8StringEncoding] mutableCopy];
else
ivData = (NSMutableData *) [iv mutableCopy]; // data or nil

#if !__has_feature(objc_arc)
[keyData autorelease];
[ivData autorelease];
#endif

// ensure correct lengths for key and iv data, based on algorithms
FixKeyLengths( algorithm, keyData, ivData );

status = CCCryptorCreate( kCCDecrypt, algorithm, options,
[keyData bytes], [keyData length], [ivData bytes],
&cryptor );

if ( status != kCCSuccess )
{
if ( error != NULL )
*error = status;
return ( nil );
}

NSData * result = [self _runCryptor: cryptor result: &status];
if ( (result == nil) && (error != NULL) )
*error = status;

CCCryptorRelease( cryptor );

return ( result );
}

@end

@implementation NSData (CommonHMAC)

- (NSData *) HMACWithAlgorithm: (CCHmacAlgorithm) algorithm
{
return ( [self HMACWithAlgorithm: algorithm key: nil] );
}

- (NSData *) HMACWithAlgorithm: (CCHmacAlgorithm) algorithm key: (id) key
{
NSParameterAssert(key == nil || [key isKindOfClass: [NSData class]] || [key isKindOfClass: [NSString class]]);

NSData * keyData = nil;
if ( [key isKindOfClass: [NSString class]] )
keyData = [key dataUsingEncoding: NSUTF8StringEncoding];
else
keyData = (NSData *) key;

// this could be either CC_SHA1_DIGEST_LENGTH or CC_MD5_DIGEST_LENGTH. SHA1 is larger.
unsigned char buf[CC_SHA1_DIGEST_LENGTH];
CCHmac( algorithm, [keyData bytes], [keyData length], [self bytes], [self length], buf );

return ( [NSData dataWithBytes: buf length: (algorithm == kCCHmacAlgMD5 ? CC_MD5_DIGEST_LENGTH : CC_SHA1_DIGEST_LENGTH)] );
}

@end

个人博客: 🏡 ForgetSou


-------------本文结束感谢您的阅读-------------
坚持原创技术分享,您的支持将鼓励我继续创作!

欢迎关注我的其它发布渠道