错误的算法:C# 需要 AES 或 Rijndael
Wrong algorithm: AES or Rijndael required on c#
我有安卓代码,我试图将其转换为 C#。这是一个简单的加密 class。但是当我尝试用它解密数据时,我发现:Wrong algorithm: AES or Rijndael required
.
这是我转换后的代码:
public static string decrypt(string data)
{
byte[] dataBytes = Convert.FromBase64String(data);
SecretKey secretKey = getSecretKey(hashTheKey("ABCD"));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(2, secretKey, new IvParameterSpec(new byte[16]),
SecureRandom.getInstance("SHA1PRNG"));
var x = cipher.doFinal(dataBytes);
return System.Text.Encoding.UTF8.GetString(x);
}
public static SecretKey getSecretKey(char[] key)
{
var secretKeyType = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
var secretkey = secretKeyType.generateSecret(new PBEKeySpec(key,
System.Text.Encoding.UTF8
.GetBytes("ABCD"),
100, 128)).getEncoded();
return new SecretKeySpec(secretkey, "AES/CBC/PKCS5Padding");
}
public static char[] hashTheKey(string key)
{
MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
messageDigest.update(System.Text.Encoding.UTF8.GetBytes(key));
return Convert.ToBase64String(messageDigest.digest()).ToCharArray();
}
这是我的原始 android 代码:
private char[] hashTheKey(String key) throws UnsupportedEncodingException, NoSuchAlgorithmException {
MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
messageDigest.update(key.getBytes());
return Base64.encodeToString(messageDigest.digest(),
Base64.NO_PADDING).toCharArray();
}
private SecretKey getSecretKey(char[] key) throws NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeySpecException {
return new SecretKeySpec(
SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1")
.generateSecret(new PBEKeySpec(key,
"ABCD".getBytes("UTF8"),
100, 128)).getEncoded(), "AES");
}
public String decrypt(String data) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException, InvalidKeySpecException {
byte[] dataBytes = Base64.decode(data, Base64.DEFAULT);
SecretKey secretKey = getSecretKey(hashTheKey("ABCD"));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(2, secretKey, new IvParameterSpec(new byte[16]),
SecureRandom.getInstance("SHA1PRNG"));
return new String(cipher.doFinal(dataBytes));
}
C# 不会将加密算法处理为 Android 或 java 您是否必须使用 AES 或 Rijndael 算法,因为您可以看到将简单文本转换为加密 Base64 的错误并且反之亦然,您可以在 C#
中使用以下 class
public static class Stringcipher
{
// This constant is used to determine the keysize of the encryption algorithm in bits.
// We divide this by 8 within the code below to get the equivalent number of bytes.
private const int Keysize = 256;
// This constant determines the number of iterations for the password bytes generation function.
private const int DerivationIterations = 1000;
public static string Encrypt(string plainText, string passPhrase)
{
// Salt and IV is randomly generated each time, but is preprended to encrypted cipher text
// so that the same Salt and IV values can be used when decrypting.
var saltStringBytes = Generate256BitsOfRandomEntropy();
var ivStringBytes = Generate256BitsOfRandomEntropy();
var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
using (var symmetricKey = new RijndaelManaged())
{
symmetricKey.BlockSize = 256;
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes))
{
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
// Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes.
var cipherTextBytes = saltStringBytes;
cipherTextBytes = cipherTextBytes.Concat(ivStringBytes).ToArray();
cipherTextBytes = cipherTextBytes.Concat(memoryStream.ToArray()).ToArray();
memoryStream.Close();
cryptoStream.Close();
return Convert.ToBase64String(cipherTextBytes);
}
}
}
}
}
}
public static string Decrypt(string cipherText, string passPhrase)
{
// Get the complete stream of bytes that represent:
// [32 bytes of Salt] + [32 bytes of IV] + [n bytes of CipherText]
var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText);
// Get the saltbytes by extracting the first 32 bytes from the supplied cipherText bytes.
var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray();
// Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes.
var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray();
// Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string.
var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) * 2)).ToArray();
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
using (var symmetricKey = new RijndaelManaged())
{
symmetricKey.BlockSize = 256;
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
using (var decryptor = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes))
{
using (var memoryStream = new MemoryStream(cipherTextBytes))
{
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
var plainTextBytes = new byte[cipherTextBytes.Length];
var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
}
}
}
}
}
}
private static byte[] Generate256BitsOfRandomEntropy()
{
var randomBytes = new byte[32]; // 32 Bytes will give us 256 bits.
using (var rngCsp = new RNGCryptoServiceProvider())
{
// Fill the array with cryptographically secure random bytes.
rngCsp.GetBytes(randomBytes);
}
return randomBytes;
}
}
c# and java 正在使用相同的完善的加密算法,但调用它们的方法不同。不过仍然可以转换代码。
一个关键点是 base64 编码的不同 - C# 总是使用填充。
转换后的代码如下:
const int KeySize = 128;
static string HashTheKey(string key) {
String hashKey;
using (var sha = new SHA1Managed()) {
hashKey = Convert.ToBase64String(sha.ComputeHash(Encoding.UTF8.GetBytes(key)));
}
// beware - you're on C# now so remove the padding and add the newline to match java
return hashKey.Replace("=", "") + "\n";
}
static byte[] GetSecretKey(string password) {
var salt = Encoding.UTF8.GetBytes("JVAaVhAiddKAaghraikhmaini");
using (var pass = new Rfc2898DeriveBytes(password, salt, 65536)) {
return pass.GetBytes(KeySize / 8);
}
}
static void Main(string[] args) {
string encrypted = "vtlkQHTz7/oz2weuAAkLz2Q5c2yj2LGukF7SHJjT+TA8oRLixTQSXQ7dG1O736hyT1HJxcz0P4DzzVaO5chWKKSJQ2uPEpDQJu/fZGguqDw=";
byte[] encryptedBytes = Convert.FromBase64String(encrypted);
using (var aes = new AesManaged()) {
aes.KeySize = KeySize;
aes.Padding = PaddingMode.PKCS7;
aes.Key = GetSecretKey(HashTheKey("Android"));
// you're using the same init vector in your android code
aes.IV = new byte[16];
using (var decryptor = aes.CreateDecryptor()) {
// dumps {"barcode":"12345678","token":"cad603fc-1e53-4a95-9150-f1694baa07f9"}
Console.Out.WriteLine(Encoding.UTF8.GetString(decryptor.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length)));
}
}
}
我有安卓代码,我试图将其转换为 C#。这是一个简单的加密 class。但是当我尝试用它解密数据时,我发现:Wrong algorithm: AES or Rijndael required
.
这是我转换后的代码:
public static string decrypt(string data)
{
byte[] dataBytes = Convert.FromBase64String(data);
SecretKey secretKey = getSecretKey(hashTheKey("ABCD"));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(2, secretKey, new IvParameterSpec(new byte[16]),
SecureRandom.getInstance("SHA1PRNG"));
var x = cipher.doFinal(dataBytes);
return System.Text.Encoding.UTF8.GetString(x);
}
public static SecretKey getSecretKey(char[] key)
{
var secretKeyType = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
var secretkey = secretKeyType.generateSecret(new PBEKeySpec(key,
System.Text.Encoding.UTF8
.GetBytes("ABCD"),
100, 128)).getEncoded();
return new SecretKeySpec(secretkey, "AES/CBC/PKCS5Padding");
}
public static char[] hashTheKey(string key)
{
MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
messageDigest.update(System.Text.Encoding.UTF8.GetBytes(key));
return Convert.ToBase64String(messageDigest.digest()).ToCharArray();
}
这是我的原始 android 代码:
private char[] hashTheKey(String key) throws UnsupportedEncodingException, NoSuchAlgorithmException {
MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
messageDigest.update(key.getBytes());
return Base64.encodeToString(messageDigest.digest(),
Base64.NO_PADDING).toCharArray();
}
private SecretKey getSecretKey(char[] key) throws NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeySpecException {
return new SecretKeySpec(
SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1")
.generateSecret(new PBEKeySpec(key,
"ABCD".getBytes("UTF8"),
100, 128)).getEncoded(), "AES");
}
public String decrypt(String data) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException, InvalidKeySpecException {
byte[] dataBytes = Base64.decode(data, Base64.DEFAULT);
SecretKey secretKey = getSecretKey(hashTheKey("ABCD"));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(2, secretKey, new IvParameterSpec(new byte[16]),
SecureRandom.getInstance("SHA1PRNG"));
return new String(cipher.doFinal(dataBytes));
}
C# 不会将加密算法处理为 Android 或 java 您是否必须使用 AES 或 Rijndael 算法,因为您可以看到将简单文本转换为加密 Base64 的错误并且反之亦然,您可以在 C#
中使用以下 classpublic static class Stringcipher
{
// This constant is used to determine the keysize of the encryption algorithm in bits.
// We divide this by 8 within the code below to get the equivalent number of bytes.
private const int Keysize = 256;
// This constant determines the number of iterations for the password bytes generation function.
private const int DerivationIterations = 1000;
public static string Encrypt(string plainText, string passPhrase)
{
// Salt and IV is randomly generated each time, but is preprended to encrypted cipher text
// so that the same Salt and IV values can be used when decrypting.
var saltStringBytes = Generate256BitsOfRandomEntropy();
var ivStringBytes = Generate256BitsOfRandomEntropy();
var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
using (var symmetricKey = new RijndaelManaged())
{
symmetricKey.BlockSize = 256;
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes))
{
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
// Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes.
var cipherTextBytes = saltStringBytes;
cipherTextBytes = cipherTextBytes.Concat(ivStringBytes).ToArray();
cipherTextBytes = cipherTextBytes.Concat(memoryStream.ToArray()).ToArray();
memoryStream.Close();
cryptoStream.Close();
return Convert.ToBase64String(cipherTextBytes);
}
}
}
}
}
}
public static string Decrypt(string cipherText, string passPhrase)
{
// Get the complete stream of bytes that represent:
// [32 bytes of Salt] + [32 bytes of IV] + [n bytes of CipherText]
var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText);
// Get the saltbytes by extracting the first 32 bytes from the supplied cipherText bytes.
var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray();
// Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes.
var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray();
// Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string.
var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) * 2)).ToArray();
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
using (var symmetricKey = new RijndaelManaged())
{
symmetricKey.BlockSize = 256;
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
using (var decryptor = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes))
{
using (var memoryStream = new MemoryStream(cipherTextBytes))
{
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
var plainTextBytes = new byte[cipherTextBytes.Length];
var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
}
}
}
}
}
}
private static byte[] Generate256BitsOfRandomEntropy()
{
var randomBytes = new byte[32]; // 32 Bytes will give us 256 bits.
using (var rngCsp = new RNGCryptoServiceProvider())
{
// Fill the array with cryptographically secure random bytes.
rngCsp.GetBytes(randomBytes);
}
return randomBytes;
}
}
c# and java 正在使用相同的完善的加密算法,但调用它们的方法不同。不过仍然可以转换代码。
一个关键点是 base64 编码的不同 - C# 总是使用填充。
转换后的代码如下:
const int KeySize = 128;
static string HashTheKey(string key) {
String hashKey;
using (var sha = new SHA1Managed()) {
hashKey = Convert.ToBase64String(sha.ComputeHash(Encoding.UTF8.GetBytes(key)));
}
// beware - you're on C# now so remove the padding and add the newline to match java
return hashKey.Replace("=", "") + "\n";
}
static byte[] GetSecretKey(string password) {
var salt = Encoding.UTF8.GetBytes("JVAaVhAiddKAaghraikhmaini");
using (var pass = new Rfc2898DeriveBytes(password, salt, 65536)) {
return pass.GetBytes(KeySize / 8);
}
}
static void Main(string[] args) {
string encrypted = "vtlkQHTz7/oz2weuAAkLz2Q5c2yj2LGukF7SHJjT+TA8oRLixTQSXQ7dG1O736hyT1HJxcz0P4DzzVaO5chWKKSJQ2uPEpDQJu/fZGguqDw=";
byte[] encryptedBytes = Convert.FromBase64String(encrypted);
using (var aes = new AesManaged()) {
aes.KeySize = KeySize;
aes.Padding = PaddingMode.PKCS7;
aes.Key = GetSecretKey(HashTheKey("Android"));
// you're using the same init vector in your android code
aes.IV = new byte[16];
using (var decryptor = aes.CreateDecryptor()) {
// dumps {"barcode":"12345678","token":"cad603fc-1e53-4a95-9150-f1694baa07f9"}
Console.Out.WriteLine(Encoding.UTF8.GetString(decryptor.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length)));
}
}
}