我正在尝试在iOS中使用AES / CBC加密。解密由C#完成。 Java中的Java加密工作正常。我收到错误"填充无效,无法删除。"尝试使用iOS代码时。请帮忙。
请在下面找到C#,Java和Objective C代码。
C#代码:
namespace InternetMobileService
{
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Xml;
public class EncryptDecrypt
{
//// Replace me with a 16-byte key, share between Java and C#
/// <summary>
/// rawSecretKey values
/// </summary>
private static byte[] rawSecretKey = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
/// <summary>
/// variable field
/// </summary>
private ICryptoTransform rijndaelDecryptor;
/// <summary>
/// Initializes a new instance of the <see cref="EncryptDecrypt"/> class.
/// </summary>
/// <param name="passphrase">pass phrase</param>
public EncryptDecrypt(string passphrase)
{
byte[] passwordKey = EncodeDigest(passphrase);
RijndaelManaged rijndael = new RijndaelManaged();
this.rijndaelDecryptor = rijndael.CreateDecryptor(passwordKey, rawSecretKey);
}
public static byte[] EncodeDigest(string text)
{
SHA256CryptoServiceProvider x = new System.Security.Cryptography.SHA256CryptoServiceProvider();
byte[] data = Encoding.ASCII.GetBytes(text);
return x.ComputeHash(data);
}
public static string Encrypt(string plainText)
{
using (RijndaelManaged myRijndael = new RijndaelManaged())
{
byte[] passwordKey = EncodeDigest(System.Configuration.ConfigurationManager.AppSettings["ConstructorKey"].ToString());
byte[] encrypted = EncryptStringToBytes(plainText, passwordKey, rawSecretKey);
return Convert.ToBase64String(encrypted);
}
}
public static byte[] EncryptStringToBytes(string plainText, byte[] key, byte[] iV)
{
if (plainText == null || plainText.Length <= 0)
{
throw new ArgumentNullException("plainText");
}
if (key == null || key.Length <= 0)
{
throw new ArgumentNullException("key");
}
if (iV == null || iV.Length <= 0)
{
throw new ArgumentNullException("key");
}
byte[] encrypted;
using (RijndaelManaged rijAlg = new RijndaelManaged())
{
rijAlg.Key = key;
rijAlg.IV = iV;
ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
using (MemoryStream memorystreamEncrypt = new MemoryStream())
{
using (CryptoStream cryptostreamEncrypt = new CryptoStream(memorystreamEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter streamwriterEncrypt = new StreamWriter(cryptostreamEncrypt))
{
streamwriterEncrypt.Write(plainText);
}
encrypted = memorystreamEncrypt.ToArray();
}
}
}
return encrypted;
}
public string Decrypt(byte[] encryptedData)
{
byte[] newClearData = this.rijndaelDecryptor.TransformFinalBlock(encryptedData, 0, encryptedData.Length);
return Encoding.ASCII.GetString(newClearData);
}
public string DecryptFromBase64(string encryptedBase64)
{
return this.Decrypt(Convert.FromBase64String(encryptedBase64));
}
}
}
Java代码:
public class Crypto {
public static final String TAG = Crypto.class.getSimpleName();
// Replace me with a 16-byte key, share between Java and C#
private static Cipher aesCipher;
private static SecretKey secretKey;
private static IvParameterSpec ivParameterSpec;
private static String CIPHER_TRANSFORMATION = "AES/CBC/PKCS5Padding";
private static String CIPHER_ALGORITHM = "AES";
private static byte[] rawSecretKey = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
private static String MESSAGEDIGEST_ALGORITHM = "SHA-256";
public Crypto(String passphrase) {
byte[] passwordKey = encodeDigest(passphrase);
try {
aesCipher = Cipher.getInstance(CIPHER_TRANSFORMATION);
} catch (NoSuchAlgorithmException e) {
Log.e(TAG, "No such algorithm " + CIPHER_ALGORITHM, e);
} catch (NoSuchPaddingException e) {
Log.e(TAG, "No such padding PKCS5", e);
}
secretKey = new SecretKeySpec(passwordKey, CIPHER_ALGORITHM);
ivParameterSpec = new IvParameterSpec(rawSecretKey);
}
public byte[] decrypt(byte[] clearData) {
try {
aesCipher.init(Cipher.DECRYPT_MODE, secretKey);
} catch (InvalidKeyException e) {
e.printStackTrace();
}
byte[] decryptedData;
try {
decryptedData = aesCipher.doFinal(clearData);
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
return null;
} catch (BadPaddingException e) {
e.printStackTrace();
return null;
}
return decryptedData;
}
public String decryptAsBase64(byte[] clearData) throws IOException {
byte[] decryptedData = decrypt(clearData);
return new String(Base64New.decode(decryptedData));
}
public String encryptAsBase64(byte[] clearData) {
byte[] encryptedData = encrypt(clearData);
return Base64New.encodeBytes(encryptedData);
}
public byte[] encrypt(byte[] clearData) {
try {
aesCipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
} catch (InvalidKeyException e) {
Log.e(TAG, "Invalid key", e);
return null;
} catch (InvalidAlgorithmParameterException e) {
Log.e(TAG, "Invalid algorithm " + CIPHER_ALGORITHM, e);
return null;
}
byte[] encryptedData;
try {
encryptedData = aesCipher.doFinal(clearData);
} catch (IllegalBlockSizeException e) {
Log.e(TAG, "Illegal block size", e);
return null;
} catch (BadPaddingException e) {
Log.e(TAG, "Bad padding", e);
return null;
}
return encryptedData;
}
private byte[] encodeDigest(String text) {
MessageDigest digest;
try {
digest = MessageDigest.getInstance(MESSAGEDIGEST_ALGORITHM);
return digest.digest(text.getBytes());
} catch (NoSuchAlgorithmException e) {
Log.e(TAG, "No such algorithm " + MESSAGEDIGEST_ALGORITHM, e);
}
return null;
}
}
Obj C代码:
+ (NSString*)encryptBase64String:(NSString*)string keyString:(NSString*)keyString separateLines:(BOOL)separateLines
{
const unsigned char rawSectret[] = {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00};
NSData* rawScretdata = [NSData dataWithBytes:rawSectret length:kCCBlockSizeAES128];
NSString *shaKeyString = [self sha256HashFor:keyString];
NSData *sourceData = [string dataUsingEncoding:NSUTF8StringEncoding];
NSString *ivString = [[NSString alloc] initWithData:rawScretdata
encoding:NSUTF8StringEncoding];
NSData* Outdata = [sourceData AES128EncryptedDataWithKey:shaKeyString iv:ivString];
NSString *encodedString = [Outdata base64EncodedStringWithSeparateLines:separateLines];
return encodedString;
}
- (NSData *)AES128Operation:(CCOperation)operation key:(NSString *)key iv:(NSString *)iv
{
char keyPtr[kCCKeySizeAES128 + 1];
bzero(keyPtr, sizeof(keyPtr));
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
char ivPtr[kCCBlockSizeAES128 + 1];
bzero(ivPtr, sizeof(ivPtr));
if (iv) {
[iv getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding];
}
NSUInteger dataLength = [self length];
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(operation,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding,
keyPtr,
kCCBlockSizeAES128,
ivPtr,
[self bytes],
dataLength,
buffer,
bufferSize,
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
free(buffer);
return nil;
}
答案 0 :(得分:0)
Common Crypto使用显式密钥大小,许多其他库使用基于提供的密钥的密钥大小,因此您需要确保为Common Crypto指定正确的密钥大小,kCCKeySizeAES128
之一,{{1 },kCCKeySizeAES192
,而不是kCCKeySizeAES256
。在这种情况下,因为密钥是使用SHA-256 kCCBlockSizeAES128
派生的,所以应该指定密钥大小。
C#正在使用Rijndael,因此您必须确保指定块大小为128,这是AES支持的唯一块大小。
简单地说,如果输入相同,输出将匹配。它们是选项(模式和填充),密钥,密钥大小,数据和iv。用十六进制检查它们。
为所有三个提供测试向量:十六进制的键,输入数据和输出数据,以便我们可以测试代码。