Introduction to common iOS encryption algorithms and code practices

  • 2020-10-23 21:13:12
  • OfStack

iOS system library defines the encryption and decryption algorithms commonly used in software development, and the interface is C language form. Specifically, it includes the following categories:


 #include <CommonCrypto/CommonCryptor.h>  // Common encryption and decryption algorithms 
 #include <CommonCrypto/CommonDigest.h>  // The algorithm 
 #include <CommonCrypto/CommonHMAC.h>
 #include <CommonCrypto/CommonKeyDerivation.h>
 #include <CommonCrypto/CommonSymmetricKeywrap.h> 

The first class of commonly used encryption and decryption algorithms includes AES,DES, and the obsolete RC4, and the second class of summary algorithms includes MD5,SHA, etc. This paper mainly introduces the implementation of AES,MD5 and SHA3 most commonly used algorithms.
1. Symmetric cipher algorithm --AES
AES is mainly used in the case of the confidentiality of key data and files and the need for decryption at the same time. Its encryption key and decryption key are the same, and can be divided into 128, 192 and 2563 levels according to the key length. The larger the key length is, the greater the security will be, but the lower the performance will be. In general, the object that encrypts 1 key data is a string, and the encrypted results are also stored as a string, so the parameters and return values are strings when designing the interface. (The significance of the key parameters is explained later in the code.)

1.1 Encryption process


-(NSString *)aes256_encrypt:(NSString *)key
{
  const char *cstr = [self cStringUsingEncoding:NSUTF8StringEncoding];
  NSData *data = [NSData dataWithBytes:cstr length:self.length];
  
  // Encrypt the data 
  char keyPtr[kCCKeySizeAES256+1];
  bzero(keyPtr, sizeof(keyPtr));
  [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
  NSUInteger dataLength = [data length];
  size_t bufferSize = dataLength + kCCBlockSizeAES128;
  void *buffer = malloc(bufferSize);
  size_t numBytesEncrypted = 0;
  CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES,
                     kCCOptionPKCS7Padding | kCCOptionECBMode,
                     keyPtr, kCCKeySizeAES256,
                     NULL,
                     [data bytes], dataLength,
                     buffer, bufferSize,
                     &numBytesEncrypted);
  if (cryptStatus == kCCSuccess)
  {
    NSData *result = [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
    //base64
    return [result base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
  }else
  {
    return nil;
  }
  
}

1.2 Decryption process


-(NSString *)aes256_decrypt:(NSString *)key
{
  NSData *data = [[NSData alloc] initWithBase64EncodedData:[self dataUsingEncoding:NSASCIIStringEncoding] options:NSDataBase64DecodingIgnoreUnknownCharacters];
  
  // Decrypt the data 
  char keyPtr[kCCKeySizeAES256+1];
  bzero(keyPtr, sizeof(keyPtr));
  [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
  NSUInteger dataLength = [data length];
  size_t bufferSize = dataLength + kCCBlockSizeAES128;
  void *buffer = malloc(bufferSize);
  size_t numBytesDecrypted = 0;
  CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES,
                     kCCOptionPKCS7Padding | kCCOptionECBMode,
                     keyPtr, kCCKeySizeAES256,
                     NULL,
                     [data bytes], dataLength,
                     buffer, bufferSize,
                     &numBytesDecrypted);
  if (cryptStatus == kCCSuccess)
  {
    NSData* result = [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
    
    return [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
    
  }else
  {
    return nil;
  }
  
}

1.3 Interface invocation example


int main(int argc, const char * argv[]) {
  @autoreleasepool
  {
    
    NSString *plainText = @"O57W05XN-EQ2HCD3V-LPJJ4H0N-ZFO2WHRR-9HAVXR2J-YTYXDQPK-SJXZXALI-FAIHJV";
    NSString *key = @"12345678901234561234567890123456";
    
    NSString *cryptText = [plainText aes256_encrypt:key];
    NSLog(@"cryptText:\n%@",cryptText);
    
    NSString *newPlainText = [cryptText aes256_decrypt:key];
    NSLog(@"newPlainText:%@",newPlainText);
    
    NSString *newCrypText3 = @"u7cKED8fscZ6Czs5eU7eMXnm6/5awKzWbUFk+D1jQdZIm5JUnKgqNzI/vmiwFPvY5qD5VIfH7qAJzjDSZXNkspG/b4if5bSkdfFp/3Aysbw=";
    NSString *newPlainText3 = [newCrypText3 aes256_decrypt:key];
    NSLog(@"newPlainText3:%@",newPlainText3);

  }
  return 0;
}

1.4 Significance of key parameters
To master the use of AES algorithm, it is necessary to understand its several working modes, initialization vector, filling mode and other concepts, usually also need to keep multi-platform 1 encryption and decryption results, must do more confirmation when using. (You can use online sites to encrypt and decrypt for self-verification.)
kCCKeySizeAES256
Key length, enumerated types, and 128,192.
kCCBlockSizeAES128
The block length, with a fixed value of 16 (bytes, 128 bits), is determined by the encryption details inside the AES algorithm, but which method, mode, is for this purpose.
kCCAlgorithmAES
Algorithm name, does not distinguish 128, 192 or 258. kCCAlgorithmAES128 is only for historical reasons and has the same value as kCCAlgorithmAES.
kCCOptionPKCS7Padding
Filling mode, AES algorithm internal encryption details determine that the plaintext of AES must be an integer multiple of 64 bits, if the number of bits is insufficient, it needs to be completed. kCCOptionPKCS7Padding means to fill a few spots. For example, if 3 bits are missing, add 3 threes to the clear text. There is only one complement method for iOS, and there are more ways for other platforms, such as kCCOptionPKCS5Padding and kCCOptionZeroPadding. kCCOptionPKCS7Padding is also used for other platforms here if 1 is to be implemented.
kCCOptionECBMode
Working mode, electronic password mode. This pattern does not require an initialization vector. There are only two iOS modes, and the default is CBC mode, which is block encryption mode. In addition to the standard AES, there are other ways such as CTR,CFB and so on. Under kCCOptionECBMode mode, the requirement of multi-platform is not high, so it is recommended to use. CBC mode requires to provide the same initialization vector and keep 1 for multiple platforms. It is suitable for scenarios with higher requirements due to increased workload and higher security.
base64
For the mapping of unicode to asci code, plaintext and ciphertext may be Chinese characters or special characters before and after standard encryption, so for intuitive display, base64 encoding is usually used for plaintext and ciphertext.

2 Abstract Algorithm
The algorithm has the basic property of one-way irreversibility and is fast.
2.1 Message digest algorithm MD5
The MD5 algorithm maps any clear text (not empty) to a 32-bit string. Both digital signature and complex encryption systems are used, but the security is low when used alone due to the collision of libraries.


- (NSString *)md5HexDigest
{
  const char *cstr = [self cStringUsingEncoding:NSUTF8StringEncoding];
  
  unsigned char result[CC_MD5_DIGEST_LENGTH];
  
  CC_MD5(cstr, (unsigned int)strlen(cstr), result);
  
  NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
  
  for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++)
    [output appendFormat:@"%02x", result[i]];
  
  return output;

}

The result is stored as a hexadecimal string, and other processing such as base64 can be done.

2.2 Secure hashing algorithm SHA
SHA can be divided into 256, 484, and 5123 basic ways according to the number of digits of the results, which can be selected according to the requirements of the results. This is set through enumeration types such as CC_SHA256_DIGEST_LENGTH.


- (NSString *)sha256HexDigest
{
  const char *cstr = [self cStringUsingEncoding:NSUTF8StringEncoding];
  NSData *data = [NSData dataWithBytes:cstr length:self.length];
  
  uint8_t digest[CC_SHA256_DIGEST_LENGTH];
  
  CC_SHA256(data.bytes, (unsigned int)data.length, digest);
  
  NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
  
  for(int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++)
    [output appendFormat:@"%02x", digest[i]];
  
  return output;
}

3. To be continued, the use of RSA asymmetric password is introduced later.


Related articles: