【加密解密】加密解密介绍


参照文章

  • Base64

  • Base64编码/解码

  • 填充算法,mac与java的别

  • 片密码的干活模式

  • 分组密码

  • PKCS


Base64编码

据我说知,苹果并没有提供API来是实现Base64编码,所以需要看官在网上寻找验证,还好,这并不难

感谢Lonely__和angelababa的唤起,苹果是出Base64的API,截图如下:

苹果提供Base64API.png

Base64编码的思想是凡应用64个基本的ASCII码字符对数据进行重新编码。它将急需编码的多寡拆分成字节数组。以3个字节啊同一组。按顺序排列24 位数据,再管当时24个数据分为4组,即每组6位。再于每组的之最高位前补两个0凑足一个字节。这样就把一个3字节为一组的数据重新编码成了4个字节。当所假设编码的多少的字节数不是3底整倍数,也就是说在分组时最终一组不敷3单字节。这时在结尾一组填充1到2只0字节。并当最终编码完成后每当终极添加1到2个
“=”。

例:将对ABC进行BASE64编码:

1、首先取ABC对应的ASCII码值。A(65)B(66)C(67);

2、再获二前进制值A(01000001)B(01000010)C(01000011);

3、然后拿当时三个字节的二进制码接起来(010000010100001001000011);

4、
再为6各类为单位分为4单数据块,并在高位填充两只0后形成4只字节的编码后的价值,(00010000)(00010100)(00001001)(00000011),其中加色部分为真数据;

5、再将这四独字节数据转发成10前进制数得(16)(20)(9)(3);

6、最后根据BASE64给来的64个基本字符表,查出对应的ASCII码字符(Q)(U)(J)(D),这里的值实际就是是数量在字符表中的目录。

Base64编码表

解码过程就是是把4单字节再还原成3只字节再因不同的多寡形式将字节数组重新整理成数据。

Base64很直观的目的就是叫二进制文件转发为64独核心的ASCII码字符。

AES

系吧并无直接提供诸如DES、AES的API,但是提供了加密解密的相关操作CommonCrypto,DES或者AES的落实,需要我们协调包装一下。

加密凡由于算法/模式/填充整合的,算法是DES,AES等,
模式是EBC,CBC等,iOS和Android的填是休同等的:

mac支持:

NoPadding (NoPadding就是不填充,相当给由定义填充)

PKCS7Padding

而java支持:

NoPadding

ISO10126Padding

OAEPPadding, OAEPWith<digest>And<mgf>Padding

PKCS1Padding

PKCS5Padding

SSL3Padding

紧接下去我们引入一些背景知识:

每当密码学中,分组加密(Block
cipher,又如分块加密),是同栽对称密钥算法。它将公开分成多单相当丰富之模块(block),使用规定的算法和针对性如密钥对每组分别加密解密。分组加密是极其重要的加密协议组成,其中突出的如DES和AES作为美国政府决定的业内加密算法,应用领域从电子邮件加密到银行交易转帐,非常广阔。

密码学中的工作模式:

极致早出现的工作模式,ECB,CBC,OFB和CFB可以追溯至1981年。2001年,NIST修订了那先发布的办事模式工作列表,加入了AES,并投入了CTR模式。最后,在2010年1月,NIST加入了XTS-AES,而其他的可信模式并没呢NIST所认证。例如CTS是同等栽密文窃取的模式,许多大面积的密码学运行库提供了这种模式。

密码学中,块密码的行事模式允许使用及一个块密码密钥对多于一片的数额进行加密,并保证其安全性。块密码自身只能加密长度等密码片长的单块数据,若一旦加密变长数据,则数要先行被分也有单身的密码块。通常而言,最后一块数据也得动用相当填充方式拿数据扩展至适合密码块大小的长短。一种工作模式描述了加密每一样数据块的历程,并常常以基于一个习以为常号称初始化向量的叠加输入值为拓展随机化,以保安全。

初始化向量

初始化向量(IV,Initialization
Vector)是成千上万工作模式遭遇用来随机化加密的平等块数据,因此好由同的明白,相同之密钥产生不同之密文,而不论是需另行有密钥,避免了便相当复杂的当下同样历程。

初始化向量与密钥相比起例外的安全性要求,因此IV通常并非保密,然而当多数景被,不该以运用同一密钥的事态下零星次于下以及一个IV。对于CBC和CFB,重用IV会导致泄露明文首单片的一点信息,亦包括个别独不等消息备受平等之前缀。对于OFB和CTR而言,重用IV会导致全盘失去安全性。另外,在CBC模式受到,IV在加密常常须是力不从心预测的;特别之,在博落实着以的产生IV的不二法门,例如SSL2.0用到的,即采取上一个音的终极一片密文作为下一个消息之IV,是休安全的。

专注:ECB模式不欲初始化向量,之所以提一句,是因自为此的ECB模式。

填充

片密码只能针对规定长度的多寡块进行处理,而信息之长短一般是可变的。因此有模式(即ECB和CBC)需要最终一块当加密前进行填空。有数种填充方法,其中最为简单易行的一样种是在平文的最终填充空字符以使该长度为片长的整数加倍,但不能不确保得过来平文的初长度;例如,若平文是C语言风格的字符串,则只来拧尾会有空字符。稍微复杂一点底方式则是土生土长之DES使用的方法,即于数后补充加一个1位,再上加足够的0位直到满足块长的要求;若消息长度刚好符合块长,则长一个填写充块。最复杂的则是针对CBC的方,例如密文窃取,残块终结等,不见面发生额外的密文,但会加部分复杂度。布鲁斯·施奈尔以及尼尔斯·弗格森提出了点儿种简单的可能:添加一个值也128的字节(十六进制的80),再因为0字节填写满最后一个块;或朝向最终一个片填充n个值均为n的字节。

CFB,OFB和CTR模式不需要针对长不呢密码块大小整数加倍的信进行特别的处理。因为这些模式是透过对块密码的输出和平文进行异或工作之。最后一个平文块(可能是未整的)与密钥流块的前方几个字节异或后,产生了和该平文块大小一样之密文块。流密码的之特性使得其可以动用在需要密文和平文数据长严格等的场合,也足以以在为流动式传输数据而未便宜进行填的场子。

留神:ECB模式是索要填写的。

ECB:
顶简便的加密模式就是为电子密码本(Electronic
codebook,ECB)模式。需要加密的信息据块密码的片大小为分为数只片,并对准每个片进行单独加密。

ECB加密

ECB解密

论方的短处在于同的平文块会吃加密成相同之密文块;因此,它不克怪好的隐身数据模式。在某些场合,这种办法无能够提供严格的数量保密性,因此并无引进用于密码协议被。下面的事例显示了ECB在密文中显示平文的模式的水准:该图像的一个位图版本(上图)通过ECB模式或者会见给加密成中图,而非ECB模式通常会将该加密成最下图。

原图

利用ECB模式加密

供了伪随机性的非ECB模式

原图是以CBC,CTR或其他其他的更安全的模式加密最下图或产生的结果——与随机噪声无异。注意最下图看起的随机性并无克表示图像已经给平安之加密;许多未安全的加密法也或发生这种“随机的”输出。

ECB模式吧会招使用她的商不能够提供数据完整性保护,易遭到重放攻击的熏陶,因此每个片是因完全相同的章程解密之。例如,“梦幻之星在线:蓝色脉冲”在线电子游戏以ECB模式之Blowfish密码。在密钥交换系统被破解而产生重复简约的破解方式前,作弊者重复通过发送加密的“杀死怪物”消息包以私的迅猛增加阅历值。

外模式于是即非进行了,详情请转片密码的做事模式
,进一步询问CBC、CFB、OFB、CTR等模式。

管极重点的函数摘出来解释一下:

/*!
    @function   CCCrypt
    @abstract   Stateless, one-shot encrypt or decrypt operation.
                This basically performs a sequence of CCCrytorCreate(),
                CCCryptorUpdate(), CCCryptorFinal(), and CCCryptorRelease().

    @param      alg             Defines the encryption algorithm.


    @param      op              Defines the basic operation: kCCEncrypt or
                    kCCDecrypt.

    @param      options         A word of flags defining options. See discussion
                                for the CCOptions type.

    @param      key             Raw key material, length keyLength bytes. 

    @param      keyLength       Length of key material. Must be appropriate 
                                for the select algorithm. Some algorithms may 
                                provide for varying key lengths.

    @param      iv              Initialization vector, optional. Used for 
                                Cipher Block Chaining (CBC) mode. If present, 
                                must be the same length as the selected 
                                algorithm's block size. If CBC mode is
                                selected (by the absence of any mode bits in 
                                the options flags) and no IV is present, a 
                                NULL (all zeroes) IV will be used. This is 
                                ignored if ECB mode is used or if a stream 
                                cipher algorithm is selected. 

    @param      dataIn          Data to encrypt or decrypt, length dataInLength 
                                bytes. 

    @param      dataInLength    Length of data to encrypt or decrypt.

    @param      dataOut         Result is written here. Allocated by caller. 
                                Encryption and decryption can be performed
                                "in-place", with the same buffer used for 
                                input and output. 

    @param      dataOutAvailable The size of the dataOut buffer in bytes.  

    @param      dataOutMoved    On successful return, the number of bytes
                    written to dataOut. If kCCBufferTooSmall is
                returned as a result of insufficient buffer
                space being provided, the required buffer space
                is returned here. 

    @result     kCCBufferTooSmall indicates insufficent space in the dataOut
                                buffer. In this case, the *dataOutMoved 
                                parameter will indicate the size of the buffer
                                needed to complete the operation. The 
                                operation can be retried with minimal runtime 
                                penalty. 
                kCCAlignmentError indicates that dataInLength was not properly 
                                aligned. This can only be returned for block 
                                ciphers, and then only when decrypting or when 
                                encrypting with block with padding disabled. 
                kCCDecodeError  Indicates improperly formatted ciphertext or
                                a "wrong key" error; occurs only during decrypt
                                operations. 
 */  

CCCryptorStatus CCCrypt(
    CCOperation op,         /* 枚举值,确认是加密操作,还是解密操作 */
    CCAlgorithm alg,        /* 枚举值,确认加解密的算法,如kCCAlgorithmAES128、kCCAlgorithmDES */
    CCOptions options,      /* 枚举值,kCCOptionPKCS7Padding | kCCOptionECBMode,经我调查,这样就是ECB模式,并以PKCS7来填充*/
    const void *key,
    size_t keyLength,
    const void *iv,         /* 初始化向量(NULLoptional initialization vector),ECB模式写NULL就行 */
    const void *dataIn,     /* optional per op and alg */
    size_t dataInLength,
    void *dataOut,          /* data RETURNED here */
    size_t dataOutAvailable,
    size_t *dataOutMoved)  

地方说到,iOS和Android填充是勿同等的,那怎么收拾?据说,PKCS7Padding是兼容PKCS5Padding的,我以跟安卓同测试中,确实没问题。

将自家为此的AES加密摘出来吧:

本身因此之是一个NSData类目NSData+AES,密钥是128各类之,即16只字节,加密解密方法的贯彻如下(记得引#import <CommonCrypto/CommonCryptor.h>):

加密:

- (NSData *)AES128EncryptWithKey:(NSString *)key
{
    // 'key' should be 32 bytes for AES256, will be null-padded otherwise
    char keyPtr[kCCKeySizeAES128+1]; // room for terminator (unused)
    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)

    // fetch key data
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

    NSUInteger dataLength = [self length];

    //See the doc: For block ciphers, the output size will always be less than or
    //equal to the input size plus the size of one block.
    //That's why we need to add the size of one block here
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);

    size_t numBytesEncrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding | kCCOptionECBMode,
                                          keyPtr, kCCKeySizeAES128,
                                          NULL /* initialization vector (optional) */,
                                          [self bytes], dataLength, /* input */
                                          buffer, bufferSize, /* output */
                                          &numBytesEncrypted);
    if (cryptStatus == kCCSuccess) {
        //the returned NSData takes ownership of the buffer and will free it on deallocation
        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
    }

    free(buffer); //free the buffer;
    return nil;
}  

解密:

- (NSData *)AES128DecryptWithKey:(NSString *)key {
    // 'key' should be 32 bytes for AES256, will be null-padded otherwise
    char keyPtr[kCCKeySizeAES128+1]; // room for terminator (unused)
    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)

    // fetch key data
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

    NSUInteger dataLength = [self length];

    //See the doc: For block ciphers, the output size will always be less than or
    //equal to the input size plus the size of one block.
    //That's why we need to add the size of one block here
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);

    size_t numBytesDecrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding| kCCOptionECBMode,
                                          keyPtr, kCCKeySizeAES128,
                                          NULL /* initialization vector (optional) */,
                                          [self bytes], dataLength, /* input */
                                          buffer, bufferSize, /* output */
                                          &numBytesDecrypted);

    if (cryptStatus == kCCSuccess) {
        //the returned NSData takes ownership of the buffer and will free it on deallocation
        return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
    }

    free(buffer); //free the buffer;
    return nil;
}  

相关文章