逆向IOS个人开发

加密算法 - DES,AES, RSA, MD5, SHA, H

2018-05-04  本文已影响253人  reboot_q

在介绍加密算法之前, 先介绍一下 base64:

0. base64

Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法。可查看RFC2045~RFC2049,上面有MIME的详细规范。
Base64编码是从二进制到字符的过程,可用于在HTTP环境下传递较长的标识信息。例如,在Java Persistence系统Hibernate中,就采用了Base64来将一个较长的唯一标识符(一般为128-bit的UUID)编码为一个字符串,用作HTTP表单和HTTP GET URL中的参数。在其他应用程序中,也常常需要把二进制数据编码为适合放在URL(包括隐藏表单域)中的形式。此时,采用Base64编码具有不可读性,需要解码后才能阅读。


转换实例:
转换前 11111111, 11111111, 11111111 (二进制)
转换后 00111111, 00111111, 00111111, 00111111 (二进制)
上面的三个字节是原文,下面的四个字节是转换后的Base64编码,其前两位均为0。
转换后,我们用一个码表来得到我们想要的字符串(也就是最终的Base64编码),这个表是这样的:(摘自RFC2045)

1. 哈希(散列)算法

1.1 MD5

MD5Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致。是计算机广泛使用的杂凑算法之一(又译摘要算法哈希算法),主流编程语言普遍已有MD5实现。将数据(如汉字)运算为另一固定长度值,是杂凑算法的基础原理,MD5的前身有MD2、MD3MD4

MD5的作用是让大容量信息在用数字签名软件签署私人密钥前被"压缩"成一种保密的格式(就是把一个任意长度的字节串变换成一定长的十六进制数字串)。除了MD5以外,其中比较有名的还有sha-1RIPEMD以及Haval等。

1.2 SHA

安全散列算法(英语:Secure Hash Algorithm,缩写为SHA)是一个密码散列函数家族,是FIPS所认证的安全散列算法。能计算出一个数字消息所对应到的,长度固定的字符串(又称消息摘要)的算法。且若输入的消息不同,它们对应到不同字符串的机率很高。

1.3 HMAC

HMAC Hash-based Message Authentication Code, 哈希消息认证码.

算法公式 : HMAC(K,M)=H(K⊕opad∣H(K⊕ipad∣M)) [1]
H 代表所采用的HASH算法(如SHA-256)
K 代表认证密码
Ko 代表HASH算法的密文
M 代表一个消息输入
B 代表H中所处理的块大小,这个大小是处理块大小,而不是输出hash的大小
如,SHA-1和SHA-256 B = 64
SHA-384和SHA-512 B = 128
L 表示hash的大小
Opad 用0x5c重复B次
Ipad 用0x36重复B次
Apad 用0x878FE1F3重复(L/4)次

认证流程
(1) 先由客户端向服务器发出一个验证请求。
(2) 服务器接到此请求后生成一个随机数并通过网络传输给客户端。
(3) 客户端将收到的随机数提供给ePass,由ePass使用该随机数与存储在ePass中的密钥进行HMAC-MD5运算并得到一个结果作为认证证据传给服务器(此为响应)。
(4) 与此同时,服务器也使用该随机数与存储在服务器数据库中的该客户密钥进行HMAC-MD5运算,如果服务器的运算结果与客户端传回的响应结果相同,则认为客户端是一个合法用户

+ (NSData *)hmacSha1WithData:(NSData *)hashData hmacKey:(NSString *)key
{
    unsigned char *digest;
    digest = malloc(CC_SHA1_DIGEST_LENGTH);
    const char *cKey = [key cStringUsingEncoding:NSUTF8StringEncoding];

    CCHmac(kCCHmacAlgSHA1, cKey, strlen(cKey), [hashData bytes], [hashData length], digest);
    NSData *hmacData = [NSData dataWithBytes:digest length:CC_SHA1_DIGEST_LENGTH];
    free(digest);
    cKey = nil;

    return hmacData;
}

2. 对称加密算法

加密步骤如下:
1)首先将数据按照8个字节一组进行分组得到D1D2......Dn(若数据不是8的整数倍,用指定的PADDING数据补位)
2)第一组数据D1与初始化向量I异或后的结果进行DES加密得到第一组密文C1(初始化向量I为全零)
3)第二组数据D2与第一组的加密结果C1异或以后的结果进行DES加密,得到第二组密文C2
4)之后的数据以此类推,得到Cn
5)按顺序连为C1C2C3......Cn即为加密结果。

解密是加密的逆过程,步骤如下:
1)首先将数据按照8个字节一组进行分组得到C1C2C3......Cn
2)将第一组数据进行解密后与初始化向量I进行异或得到第一组明文D1(注意:一定是先解密再异或)
3)将第二组数据C2进行解密后与第一组密文数据进行异或得到第二组数据D2
4)之后依此类推,得到Dn
5)按顺序连为D1D2D3......Dn即为解密结果。

这里注意一点,解密的结果并不一定是我们原来的加密数据,可能还含有你补得位,一定要把补位去掉才是你的原来的数据。

2.1 DES加密

DES全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法,1977年被美国联邦政府的国家标准局确定为联邦资料处理标准(FIPS),并授权在非密级政府通信中使用,随后该算法在国际上广泛流传开来。需要注意的是,在某些文献中,作为算法的DES称为数据加密算法(Data Encryption Algorithm,DEA),已与作为标准的DES区分开来。

DES设计中使用了分组密码设计的两个原则:混淆( confusion)和扩散(diffusion),其目的是抗击敌手对密码系统的统计分析。混淆是使密文的统计特性与密钥的取值之间的关系尽可能复杂化,以使密钥和明文以及密文之间的依赖性对密码分析者来说是无法利用的。扩散的作用就是将每一位明文的影响尽可能迅速地作用到较多的输出密文位中,以便在大量的密文中消除明文的统计结构,并且使每一位密钥的影响尽可能迅速地扩展到较多的密文位中,以防对密钥进行逐段破译。

2.2 3DES

2.3 AES加密

AES加密算法即密码学中的高级加密标准(Advanced Encryption Standard,AES),又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院 (NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。2006年,高级加密标准已然成为对称密钥加密中最流行的算法之一。该算法为比利时密码学家[Joan Daemen](javascript:linkredwin('Joan Daemen'); "Joan Daemen")和[Vincent Rijmen](javascript:linkredwin('Vincent Rijmen'); "Vincent Rijmen")所设计,结合两位作者的名字,以Rijndael之命名之,投稿高级加密标准的甄选流程。(Rijdael的发音近于 "Rhinedoll"。)

加密过程是先加密,再base64编码; 解密过程是先base64解码,再解密

加密:

    - (NSString *)encryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv {

      // 设置秘钥
      NSData *keyData = [keyString dataUsingEncoding:NSUTF8StringEncoding];
      uint8_t cKey[self.keySize];
      bzero(cKey, sizeof(cKey));
      [keyData getBytes:cKey length:self.keySize];

      // 设置iv
      uint8_t cIv[self.blockSize];
      bzero(cIv, self.blockSize);
      int option = 0;
      if (iv) {
          [iv getBytes:cIv length:self.blockSize];
          option = kCCOptionPKCS7Padding;
      } else {
          option = kCCOptionPKCS7Padding | kCCOptionECBMode;
      }

      // 设置输出缓冲区
      NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
      size_t bufferSize = [data length] + self.blockSize;
      void *buffer = malloc(bufferSize);

      // 开始加密
      size_t encryptedSize = 0;

      /**
       1. 加密/解密
       2. 加密算法(AES/DES)
       3. 加密方式(ECB/CBC)
       4. 加密秘钥
       5. 秘钥长度
       6. iv 初始向量, ECB 传 nil
       7. 待加密数据
       8. 数据长度
       9. 密文缓存区地址
       10. 密文长度
       11. 加密结果的大小(地址)
       */
      CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
                                      self.algorithm,
                                      option,
                                      cKey,
                                      self.keySize,
                                      cIv,
                                      [data bytes],
                                      [data length],
                                      buffer,
                                      bufferSize,
                                      &encryptedSize);

      NSData *result = nil;
      if (cryptStatus == kCCSuccess) {
           result = [NSData dataWithBytesNoCopy:buffer length:encryptedSize];
      } else {    
          free(buffer);
          NSLog(@"[错误] 加密失败|状态编码: %d", cryptStatus);
      }

      return [result base64EncodedStringWithOptions:0];
   }

解密:

  - (NSString *)decryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv {

// 设置秘钥
NSData *keyData = [keyString dataUsingEncoding:NSUTF8StringEncoding];
uint8_t cKey[self.keySize];
bzero(cKey, sizeof(cKey));
[keyData getBytes:cKey length:self.keySize];

// 设置iv
uint8_t cIv[self.blockSize];
bzero(cIv, self.blockSize);
int option = 0;
if (iv) {
    [iv getBytes:cIv length:self.blockSize];
    option = kCCOptionPKCS7Padding;
} else {
    option = kCCOptionPKCS7Padding | kCCOptionECBMode;
}

// 设置输出缓冲区
NSData *data = [[NSData alloc] initWithBase64EncodedString:string options:0];
size_t bufferSize = [data length] + self.blockSize;
void *buffer = malloc(bufferSize);

// 开始解密
size_t decryptedSize = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
                                      self.algorithm,
                                      option,
                                      cKey,
                                      self.keySize,
                                      cIv,
                                      [data bytes],
                                      [data length],
                                      buffer,
                                      bufferSize,
                                      &decryptedSize);

NSData *result = nil;
if (cryptStatus == kCCSuccess) {
    result = [NSData dataWithBytesNoCopy:buffer length:decryptedSize];
} else {
    free(buffer);
    NSLog(@"[错误] 解密失败|状态编码: %d", cryptStatus);
}

return [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
}

3 非对称加密算法(RSA)

未完待续...

上一篇 下一篇

猜你喜欢

热点阅读