【发布时间】:2014-03-26 04:42:51
【问题描述】:
是的,所以我有一个 API 正在尝试向其传递密码。我需要将密码作为加密的 AES 256 字符串发送。我已经使用 Rijndael 用 C# 编写了这个过程的工作实现。如下:
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;
这有效,并且输出:
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);
IV、密钥和密码都与 C# 示例中使用的相同。加密方法如下:
- (NSData *)AES256Encryptor1:(NSString *)dataString WithKey:(NSString *)key iv:(NSString *)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:NSASCIIStringEncoding];
NSLog(@"keyPtr: '%s'", keyData.bytes);
NSData *dataToEncrypt = [dataString dataUsingEncoding:NSASCIIStringEncoding];
NSData *ivData = [iv dataUsingEncoding:NSASCIIStringEncoding];
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;
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;
}
但这会返回与 C# 完全不同的东西。我得到以下 base 64 字符串:
faAoHJ/oBGVpi0LHi6fhzrWMT9+z/uqYm1bdHOKrs6o=
现在,显然这完全是错误的长度。我想知道 Common Crypto 是否附加了一个额外的块?它使用的缓冲区大小为 32,但我不知道这是否正确。
如果有人可以就我是否做了一些愚蠢的事情提供一些建议,并可能为我提供一个解决方案或一些关于如何找到真正有用的解决方案的提示!
谢谢!
亚当
编辑:
根据以下 cmets 之一的要求,以下是每个示例的相应输出:
keyData (keyPTR) (Obj-C): WebServices_TestKeyT218adje2s83a
DataToEncrypt (Obj-C):
DataToEncrypt (C#):6164616d31320a0a0a0a0a0a0a0a0a0a
IVData (Obj-C):
IVData (C#): 4fac1f39980fd10d6eab481a107a3cc3
Obj-C 和 C# 预加密中的所有值都相同。在我开始尝试加密任何东西之前,我确保我做对了,所以它应该有所有正确的输入。
编辑 2:
感谢下面的评论者 Zaph 指出我在 Obj-C 中指定了填充,但在 C# 中没有指定,我现在有一个长度正确的字符串。当我现在运行它时,我得到了字符串:
MO8yM8RSN+xEBV6/r6Mx5A==
C#中的字符串为:V0xd7lMUWfJjlWpXJKzjPw==
【问题讨论】:
-
我没有看到 C# 版本指定了填充,这是默认值吗?它是否使用 PKCS7Padding?
-
非常好!我已在 Obj-C 中将其更改为 0,现在我有一个正确长度的字符串!它仍然不是正确的字符串,但它现在是一个有效的长度!我会更新问题以反映这一点。
-
数据长度始终为 16,块大小为 32,所以应该没问题。再次感谢!
标签: c# ios objective-c encryption aes