???????公司接口需要加密裁僧,因此需要iOS或android端夜牡、.NET服務(wù)器端實現(xiàn)同樣的加密解密方式愈案。
???????原本在項目中有DES加密方式的實現(xiàn)蚊锹,用于保存賬號密碼以便App下次打開時自動登錄最爬,加密解密在本地都無問題镐捧。但是使用同樣的加密方法傳輸?shù)椒?wù)器诊霹,服務(wù)器居然無法還原原始字符串幢泼。
以下是iOS端加密和解密的方法:
static Byte iv[] = {1,2,3,4,5,6,7,8};
+ (NSString *) encryptUseDES:(NSString *)plainText key:(NSString *)key
{
NSString *ciphertext = nil;
const char *textBytes = [plainText UTF8String];
NSUInteger dataLength = [plainText length];
unsigned char buffer[1024];
memset(buffer, 0, sizeof(char));
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmDES,
kCCOptionPKCS7Padding,
[key UTF8String], kCCKeySizeDES,
iv,
textBytes,
dataLength,
buffer, 1024,
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
NSData *data = [NSData dataWithBytes:buffer length:(NSUInteger)numBytesEncrypted];
ciphertext =[GTMBase64 stringByEncodingData:data];
}
return ciphertext;
}
+ (NSString*)decryptUseDES:(NSString*)cipherText key:(NSString*)key {
NSData* cipherData = [GTMBase64 decodeString:cipherText];
unsigned char buffer[1024];
memset(buffer, 0, sizeof(char));
size_t numBytesDecrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
kCCAlgorithmDES,
kCCOptionPKCS7Padding,
[key UTF8String],
kCCKeySizeDES,
iv,
[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];
}
return plainText;
}
</br>
于是開始走上查找原因的路。
???????首先洁仗,由于本地的加密和解密正常能用层皱,懷疑可能是服務(wù)器解密函數(shù)的問題,于是讓服務(wù)器進(jìn)行加密解密驗證京痢,發(fā)現(xiàn)沒有問題奶甘。
???????然后對比兩邊的加密結(jié)果,對同一字符串使用同一個key加密祭椰,服務(wù)器的值為aDcUJMile6I=
臭家,而iOS端的值是 CHgXZ9ukWr0=
钉赁,值不同但是比較相似携茂。
???????然后查看OC和C#的實現(xiàn),詳細(xì)比對加密函數(shù)的各項參數(shù)讳苦,終于發(fā)現(xiàn)了原因所在。DES參數(shù)包括工作模式(包括電子密碼本ECB膝藕、加密分組鏈接CBC蝗肪、加密反饋CFB和OFB四種模式)、填充模式怀各、加密密鑰胰苏、初始化向量法焰、字符串編碼格式等陕赃。
問題的原因就在于初始化向量的不同。
下面分析一下兩端實現(xiàn)中使用的參數(shù)。
服務(wù)器的C#代碼類似于:
public string Encrypt(string pToEncrypt, string sKey)
{
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
byte[] inputByteArray = Encoding.Default.GetBytes(pToEncrypt);
des.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
des.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(),CryptoStreamMode.Write);
cs.Write(inputByteArray, 0, inputByteArray.Length);
cs.FlushFinalBlock();
StringBuilder ret = new StringBuilder();
foreach(byte b in ms.ToArray())
{
ret.AppendFormat("{0:X2}", b);
}
ret.ToString();
return ret.ToString();
}
和我本地加密參數(shù)相比:編碼格式都采用UTF8編碼怜校,工作模式一致胰丁,填充模式都采用 PKCS7方式蒲祈,加密密鑰也一致,但是初始向量IV不一樣,我本地使用了自定義的字符,而服務(wù)器使用密鑰key。
于是,將本地代碼修改夷恍,使用密鑰key作為偏移量指黎。再次測試時服務(wù)器終于可以正確解密了朋凉。
簡而言之,不同平臺協(xié)同工作時,采用原理一致的方法和一致的參數(shù)非常重要吓揪,可以通過查看源代碼來確保這一點。在DES加密中焙格,要著重確定5個方面的參數(shù)是否一致,包括:編碼格式摩泪、工作模式笆焰、填充模式、加密密鑰荞驴、初始向量不皆。
</br>
附加修改后的密解和密方法:
+(NSString *)encryptUseDES:(NSString *)plainText key:(NSString *)key{
NSString *ciphertext = nil;
const char *textBytes = [plainText UTF8String];
NSUInteger dataLength = [plainText length];
unsigned char buffer[1024];
memset(buffer, 0, sizeof(char));
size_t numBytesEncrypted = 0;
const void *iv = [key UTF8String];
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmDES,
kCCOptionPKCS7Padding,
[key UTF8String], kCCKeySizeDES,
iv,
textBytes,
dataLength,
buffer, 1024,
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
NSData *data = [NSData dataWithBytes:buffer length:(NSUInteger)numBytesEncrypted];
ciphertext = [[NSString alloc] initWithData:[GTMBase64 encodeData:data] encoding:NSUTF8StringEncoding];
}
return ciphertext;
}
+ (NSString*)decryptUseDES:(NSString*)cipherText key:(NSString*)key {
NSData* cipherData = [GTMBase64 decodeString:cipherText];
unsigned char buffer[1024];
memset(buffer, 0, sizeof(char));
size_t numBytesDecrypted = 0;
const void *iv = [key UTF8String];
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
kCCAlgorithmDES,
kCCOptionPKCS7Padding,
[key UTF8String],
kCCKeySizeDES,
iv,
[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];
}
return plainText;
}