原文:http://blog.toright.com/archives/2657
在使用 php-mcrypt 函式庫進行 DES 加解密時,常常會碰到在其他平台無法正確解密資料>,是因為 PHP Mcrypt Library 沒有提供將明文訊息轉換為標準 PKCS#7 的格式 (定義在 RFC 5652) 所造成。以下程式碼說明使用 PHP mcrypt_encrypt function 依據 PKCS#7 規範
對字串進行 DES 加密,並且使用 Base64 編碼後輸出後再使用 DES 解密後的結果 (包含 iOS 的 DES 解密實作)。遵循標準的 PKCS#7 規範實作,密文在其他的程式語言中才能正確>地進行解密。以下為 PHP DES 加解密的程式碼,後面會介紹 Object-C 的加解密實作。
<?php /** * PHP DES 加密程式 * * @param $key 密鑰(八個字元內) * @param $encrypt 要加密的明文 * @return string 密文 */ function encrypt ($key, $encrypt) { // 根據 PKCS#7 RFC 5652 Cryptographic Message Syntax (CMS) 修正 Message 加入 Padding $block = mcrypt_get_block_size(MCRYPT_DES, MCRYPT_MODE_ECB); $pad = $block - (strlen($encrypt) % $block); $encrypt .= str_repeat(chr($pad), $pad); // 不需要設定 IV 進行加密 $passcrypt = mcrypt_encrypt(MCRYPT_DES, $key, $encrypt, MCRYPT_MODE_ECB); return base64_encode($passcrypt); } /** * PHP DES 解密程式 * * @param $key 密鑰(八個字元內) * @param $decrypt 要解密的密文 * @return string 明文 */ function decrypt ($key, $decrypt) { // 不需要設定 IV $str = mcrypt_decrypt(MCRYPT_DES, $key, base64_decode($decrypt), MCRYPT_MODE_ECB); // 根據 PKCS#7 RFC 5652 Cryptographic Message Syntax (CMS) 修正 Message 移除 Padding $pad = ord($str[strlen($str) - 1]); return substr($str, 0, strlen($str) - $pad); } $key = 'uuid'; $plain = '0123ABCD!@#$中文'; $encrypt = encrypt($key, $plain); $decrypt = decrypt($key, $encrypt); echo 'plain = '.$plain."\r\n"; echo 'encrypt = '.$encrypt."\r\n"; echo 'decrypt = '.$decrypt."\r\n"; ?>
plain = 0123ABCD!@#$中文 encrypt = fDDkBvvC7KJAcmU9IB6aptxMZ35cn4ZX decrypt = 0123ABCD!@#$中文
#include <CommonCrypto/CommonCryptor.h>
-(NSString*) decryptUseDES:(NSString*)cipherText key:(NSString*)key { // 利用 GTMBase64 解碼 Base64 字串 NSData* cipherData = [GTMBase64 decodeString:cipherText]; unsigned char buffer[1024]; memset(buffer, 0, sizeof(char)); size_t numBytesDecrypted = 0; // IV 偏移量不需使用 CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmDES, kCCOptionPKCS7Padding | kCCOptionECBMode, [key UTF8String], kCCKeySizeDES, nil, [cipherData bytes], [cipherData length], buffer, 1024, &numBytesDecrypted); NSString* plainText = nil; if (cryptStatus == kCCSuccess) { NSData* data = [NSData dataWithBytes:buffer length:(NSUInteger)numBytesDecrypted]; plainText = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; } return plainText; }
// 設定 key NSString* key = @"skey"; NSString* encrypt = @"fDDkBvvC7KJAcmU9IB6aptxMZ35cn4ZX"; NSString* decrypt = [self decryptUseDES:encrypt key:key]; // 輸出 NSLog(@"encrypt = %@", encrypt); NSLog(@"decrypt = %@", decrypt);
2012-06-26 16:50:28.092 test[15666:13403] encrypt = fDDkBvvC7KJAcmU9IB6aptxMZ35cn4ZX 2012-06-26 16:50:28.093 test[15666:13403] decrypt = 0123ABCD!@#$中文
-(NSString *) encryptUseDES:(NSString *)clearText key:(NSString *)key { NSData *data = [clearText dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES]; unsigned char buffer[1024]; memset(buffer, 0, sizeof(char)); size_t numBytesEncrypted = 0; CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmDES, kCCOptionPKCS7Padding | kCCOptionECBMode, [key UTF8String], kCCKeySizeDES, nil, [data bytes], [data length], buffer, 1024, &numBytesEncrypted); NSString* plainText = nil; if (cryptStatus == kCCSuccess) { NSData *dataTemp = [NSData dataWithBytes:buffer length:(NSUInteger)numBytesEncrypted]; plainText = [GTMBase64 stringByEncodingData:dataTemp]; }else{ NSLog(@"DES加密失败"); } return plainText; }
參考資料