C# iOS中的CommonCrypto与C中的Rijndael产生不同的结果#
好的,我有一个API,我正试图传递密码给它。我需要将密码作为加密的AES 256字符串发送。我已经使用Rijndael用C#编写了这个过程的工作实现。详情如下:C# iOS中的CommonCrypto与C中的Rijndael产生不同的结果#,c#,ios,objective-c,encryption,aes,C#,Ios,Objective C,Encryption,Aes,好的,我有一个API,我正试图传递密码给它。我需要将密码作为加密的AES 256字符串发送。我已经使用Rijndael用C#编写了这个过程的工作实现。详情如下: AESKey.Text = "WebServices_TestKeyT218adje2s83a"; UniqueIV.Text = "T6wfOZgP0Q1uq0gaEHo8ww=="; pwd1.Text = @"test12"; ASCIIEncoding textConverter = new ASCIIEncoding(
AESKey.Text = "WebServices_TestKeyT218adje2s83a";
UniqueIV.Text = "T6wfOZgP0Q1uq0gaEHo8ww==";
pwd1.Text = @"test12";
ASCIIEncoding textConverter = new ASCIIEncoding();
// Pad entered password to multiple of 16
int padLen = 16 - (pwd1.TextLength % 16);
count1.Text = Convert.ToString(padLen);
int totalWidth = pwd1.TextLength + padLen;
string paddedpwd = pwd1.Text.PadRight(totalWidth, (char)21);
byte[] password = textConverter.GetBytes(pwd1.Text.PadRight(totalWidth, (char)padLen));
// Decode entered IV
byte[] decodedIV = Convert.FromBase64String(UniqueIV.Text);
string DecodedIVString = System.Text.Encoding.UTF8.GetString(decodedIV);
byte[] aeskey1 = textConverter.GetBytes(AESKey.Text);
string AESKeyBytes = System.Text.Encoding.UTF8.GetString(aeskey1);
//string aeskey = AESKey.Text;
// Create a new Rijndael object
RijndaelManaged rij = new RijndaelManaged();
// Set a few starting bits...
rij.IV = decodedIV;
rij.Key = aeskey1;
rij.Mode = CipherMode.CBC;
// Generate encryptor...
ICryptoTransform encryptor = rij.CreateEncryptor();
// Memory to hold encrypted data...
byte[] encPassword = null;
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
cs.Write(password, 0, password.Length);
encPassword = new byte[ms.Length];
encPassword = ms.ToArray();
}
}
// Encode enrypted password
string encodedPassword = Convert.ToBase64String(encPassword);
EncodedPasswordBox.Text = encodedPassword;
- (NSData *)AES256Encryptor1:(NSString *)dataString WithKey:(NSString *)key iv:(NSData *)iv {
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
// fetch key data
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSASCIIStringEncoding];
NSLog(@"keyPtr: '%s'", keyPtr);
NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
NSLog(@"keyPtr: '%s'", keyData.bytes);
NSData *dataToEncrypt = [dataString dataUsingEncoding:NSUTF8StringEncoding];
NSLog(@"Data To Encrypt: %@", dataToEncrypt);
NSData *ivData = iv;
NSUInteger dataLength = [dataToEncrypt length];
NSLog(@"Data length: %d", dataLength);
//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;
size_t bufferSize = dataLength + kCCBlockSizeAES128;
NSLog(@"Buffer Size: %zu", bufferSize);
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, 0,
keyData.bytes, kCCKeySizeAES256,
ivData.bytes, // initialisation vector
dataToEncrypt.bytes,
dataToEncrypt.length, /* 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];
} else {
NSLog(@"Error: %d", cryptStatus);
}
free(buffer); //free the buffer;
return nil;
}
这是可行的,并输出:
V0xd7lMUWfJjlWpXJKzjPw==
这是web服务所接受的,没有问题。我尝试在Objective-C中复制此过程。第一种方法获取密码并进行填充等操作,然后调用加密方法:
NSString * Password = @"test12";
int padding = 16 - ([Password length] % 16);
int asciiCode = padding;
for(int i=0;i<padding;i++)
{
Password = [Password stringByAppendingString:[NSString stringWithFormat:@"%c", asciiCode]];
}
NSLog(@"Password after padding: %@", Password);
NSLog(@"Padding: %d", padding);
NSString *base64EncodedString = [[Password dataUsingEncoding:NSUTF8StringEncoding] base64EncodedStringWithOptions:0];
NSLog(@"Encoded Padded PWD: %@", base64EncodedString);
NSString * IVString = @"T6wfOZgP0Q1uq0gaEHo8ww==";
NSData * IVData = [self base64DecodeString:IVString];
NSLog(@"IVData: %@", IVData);
NSString * decodedIV = [[NSString alloc] initWithData:IVData encoding:NSASCIIStringEncoding];
NSLog(@"Decoded IV: %@", decodedIV);
NSData * CryptoPass = [self AES256Encryptor1:Password WithKey:@"WebServices_TestKeyT218adje2s83a" iv:decodedIV];
NSString * Pass1 = [self base64EncodeData:CryptoPass];
NSString* newStr = [[NSString alloc] initWithData:CryptoPass encoding:NSASCIIStringEncoding];
NSLog(@"Cryptopass B64: %@", Pass1);
NSLog(@"Cryptopass: %@", CryptoPass);
但这会返回与C#完全不同的结果。我得到以下64进制字符串:
faAoHJ/oBGVpi0LHi6fhzrWMT9+z/uqYm1bdHOKrs6o=
很明显,这是完全错误的长度。我想知道公共加密是否附加了一个额外的块?它使用的缓冲区大小为32,但我不知道这是否正确
如果有人能提供一些建议,我是否做了一些愚蠢的事情,并可能为我提供一个解决方案或一些线索,如何达到一个真正有帮助的
谢谢
亚当
编辑:
根据以下评论之一的要求,以下是每个示例的适当输出:
keyData(keyPTR)(Obj-C):WebServices_testkeyt218adge2s83a
数据加密(Obj-C):
数据加密(C#):6164616D31320A0A
IVData(Obj-C):
IVData(C#):4FAC1F3990FD10D6EAB481A107A3CC3
Obj-C和C#预加密中的所有值都相同。在我开始尝试加密任何东西之前,我确保我正确地理解了这一点,所以它应该有所有正确的输入
编辑2:
感谢下面的评论员Zaph指出我在Obj-C中指定了填充,但在C#中没有指定,现在我有了一个长度正确的字符串。当我现在运行它时,我得到字符串:
MO8yM8RSN+xEBV6/r6Mx5A==
C#中的字符串是:V0xd7lMUWfJjlWpXJKzjPw==好的,解决了它
非常感谢原始问题的评论者Zaph,他为我指出了关于PKCS7Padding的正确道路
这个问题很简单,尽管我花了一些时间才弄明白。我传入的是解码的IV字符串,而不是原始C#示例中的数据。出现故障的代码是:
NSString * decodedIV = [[NSString alloc] initWithData:IVData encoding:NSASCIIStringEncoding];
然后:
NSData * CryptoPass = [self AES256Encryptor1:Password WithKey:@"key" iv:decodedIV];
其中,第一行不应该存在,我应该直接将IVData传递进来:
NSData * CryptoPass = [self AES256Encryptor1:Password WithKey:@"key" iv:IVData];
并将加密方法修改如下:
AESKey.Text = "WebServices_TestKeyT218adje2s83a";
UniqueIV.Text = "T6wfOZgP0Q1uq0gaEHo8ww==";
pwd1.Text = @"test12";
ASCIIEncoding textConverter = new ASCIIEncoding();
// Pad entered password to multiple of 16
int padLen = 16 - (pwd1.TextLength % 16);
count1.Text = Convert.ToString(padLen);
int totalWidth = pwd1.TextLength + padLen;
string paddedpwd = pwd1.Text.PadRight(totalWidth, (char)21);
byte[] password = textConverter.GetBytes(pwd1.Text.PadRight(totalWidth, (char)padLen));
// Decode entered IV
byte[] decodedIV = Convert.FromBase64String(UniqueIV.Text);
string DecodedIVString = System.Text.Encoding.UTF8.GetString(decodedIV);
byte[] aeskey1 = textConverter.GetBytes(AESKey.Text);
string AESKeyBytes = System.Text.Encoding.UTF8.GetString(aeskey1);
//string aeskey = AESKey.Text;
// Create a new Rijndael object
RijndaelManaged rij = new RijndaelManaged();
// Set a few starting bits...
rij.IV = decodedIV;
rij.Key = aeskey1;
rij.Mode = CipherMode.CBC;
// Generate encryptor...
ICryptoTransform encryptor = rij.CreateEncryptor();
// Memory to hold encrypted data...
byte[] encPassword = null;
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
cs.Write(password, 0, password.Length);
encPassword = new byte[ms.Length];
encPassword = ms.ToArray();
}
}
// Encode enrypted password
string encodedPassword = Convert.ToBase64String(encPassword);
EncodedPasswordBox.Text = encodedPassword;
- (NSData *)AES256Encryptor1:(NSString *)dataString WithKey:(NSString *)key iv:(NSData *)iv {
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
// fetch key data
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSASCIIStringEncoding];
NSLog(@"keyPtr: '%s'", keyPtr);
NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
NSLog(@"keyPtr: '%s'", keyData.bytes);
NSData *dataToEncrypt = [dataString dataUsingEncoding:NSUTF8StringEncoding];
NSLog(@"Data To Encrypt: %@", dataToEncrypt);
NSData *ivData = iv;
NSUInteger dataLength = [dataToEncrypt length];
NSLog(@"Data length: %d", dataLength);
//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;
size_t bufferSize = dataLength + kCCBlockSizeAES128;
NSLog(@"Buffer Size: %zu", bufferSize);
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, 0,
keyData.bytes, kCCKeySizeAES256,
ivData.bytes, // initialisation vector
dataToEncrypt.bytes,
dataToEncrypt.length, /* 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];
} else {
NSLog(@"Error: %d", cryptStatus);
}
free(buffer); //free the buffer;
return nil;
}
所以,我希望这能帮助其他人,因为这让我有点头疼
谢谢
Adam您尚未显示keyData、dataToEncrypt、ivData或要返回的数据的NSLog输出。它们是否与C值相同?请将此输出添加到您的问题中。将操作分为三部分进行调试:准备解密输入、解密、后处理结果。然后焦点可以应用于执行不正确的代码 我看不出C#版本指定了填充,这是默认值吗?它是否使用PKCS7Padding 如果不指定填充,则数据必须是块大小的精确倍数
使用数据转储而不是字符转储检查密钥数据。NSLog(@“keyData:%@”,keyData);通常使用“NSUTF8StringEncoding”而不是NSASCIIStringEncoding 我看不出C版本指定了填充,这是默认值吗?它是否使用PKCS7Padding?非常好!在Obj-C中,我已将其更改为0,现在我有一个长度正确的字符串!它仍然不是正确的字符串,但它现在是有效的长度!我将更新问题以反映这一点。数据长度始终为16,块大小为32,这样就可以了。再次感谢!你有iOS中的解密解决方案吗?目前,我有c#加密字符串,但在iOS中解密它时遇到问题。我被困了好几天。嗨,不幸的是没有。很抱歉