我的回答是互操作加密,希望对你有所帮助。结果可以从任何平台解密 - C# 代码或 Android/Java 代码。
- 从 C# 加密 -> 从 C#、Android、Java 解密。
- 从 Android 加密 -> 从 Android、Java、C# 解密。
- 从 Java 加密 -> 从 Java、Android、C# 解密。
- 加密结果包含密文+IV。
- IV 是使用安全随机算法生成的。
加密过程
- 转换明文 => 明文字节
- 转换密码 => passwordBytes => Sha256(passwordbytes) = passwordHashBytes
- 生成随机 IV 字节 = ivBytes
- 使用plaintextbytes 和passwordHashBytes 加密
- 加入(加密字节 + ivBytes)
- 转换为 base64 连接字节。
解密过程
- 将 base64 字符串转换为字节。
- 拆分数组 encryptedBytes、ivBytes
- 转换密码 => passwordBytes => Sha256(passwordbytes) = passwordHashBytes
- 使用 ivBytes、EncryptedBytes、PasswordHashBytes 解密
- 将 DecryptedBytes 转换为字符串
IV 在每个 Encrypt 过程中都是随机的,以获得相同文本的不同输出,避免入侵者/攻击者轻易获得原始文本。
默认模式为 CBC。
使用的编码是 UTF-8。 UTF-8 是网络上使用最广泛的编码。检查Usage of character encodings broken down by ranking
参考文献
Initialization vector
Block cipher mode of operation
C# 实现
using System;
using System.Security.Cryptography;
using System.Text;
public enum HashAlgorithm
{
MD5,
SHA1,
SHA256,
SHA384,
SHA512
}
public class HashManager
{
public static byte[] ToRawHash(byte[] data, HashAlgorithm algorithm)
{
byte[] hash;
switch (algorithm)
{
case HashAlgorithm.MD5:
MD5 md5 = MD5.Create();
hash = md5.ComputeHash(data, 0, data.Length);
return hash;
case HashAlgorithm.SHA1:
SHA1Managed sha1 = new SHA1Managed();
hash = sha1.ComputeHash(data);
return hash;
case HashAlgorithm.SHA256:
SHA256Managed sha256 = new SHA256Managed();
hash = sha256.ComputeHash(data);
return hash;
case HashAlgorithm.SHA384:
SHA384Managed sha384 = new SHA384Managed();
hash = sha384.ComputeHash(data);
return hash;
case HashAlgorithm.SHA512:
SHA512Managed sha512 = new SHA512Managed();
hash = sha512.ComputeHash(data, 0, data.Length);
return hash;
default:
throw new ArgumentException("Invalid Algorithm");
}
}
}
public class AesManager
{
private const int MAX_IV_LENGTH = 16;
private const int MAX_KEY_LENGTH = 32;
private static byte[] GenerateValidKey(byte[] keyBytes)
{
byte[] ret = new byte[MAX_KEY_LENGTH];
byte[] hash = HashManager.ToRawHash(keyBytes, HashAlgorithm.SHA256);
Array.Copy(hash, ret, MAX_KEY_LENGTH);
return ret;
}
public static byte[] EncryptRaw(byte[] PlainBytes, byte[] Key)
{
AesManaged AesAlgorithm = new AesManaged()
{
Key = GenerateValidKey(Key)
};
AesAlgorithm.GenerateIV();
var Encrypted = AesAlgorithm.CreateEncryptor().TransformFinalBlock(PlainBytes, 0, PlainBytes.Length);
byte[] ret = new byte[Encrypted.Length + MAX_IV_LENGTH];
Array.Copy(Encrypted, ret, Encrypted.Length);
Array.Copy(AesAlgorithm.IV, 0, ret, ret.Length - MAX_IV_LENGTH, MAX_IV_LENGTH);
return ret;
}
public static byte[] DecryptRaw(byte[] CipherBytes, byte[] Key)
{
AesManaged AesAlgorithm = new AesManaged()
{
Key = GenerateValidKey(Key)
};
byte[] IV = new byte[MAX_IV_LENGTH];
Array.Copy(CipherBytes, CipherBytes.Length - MAX_IV_LENGTH, IV, 0, MAX_IV_LENGTH);
AesAlgorithm.IV = IV;
byte[] RealBytes = new byte[CipherBytes.Length - MAX_IV_LENGTH];
Array.Copy(CipherBytes, RealBytes, CipherBytes.Length - MAX_IV_LENGTH);
return AesAlgorithm.CreateDecryptor().TransformFinalBlock(RealBytes, 0, RealBytes.Length); ;
}
public static String EncryptToBase64(String Plaintext, String Key)
{
byte[] PlainBytes = Encoding.UTF8.GetBytes(Plaintext);
return Base64Manager.ToBase64(EncryptRaw(PlainBytes, Encoding.UTF8.GetBytes(Key)), false);
}
public static String DecryptFromBase64(String CipherText, String Key)
{
byte[] CiPherBytes = Base64Manager.Base64ToByteArray(CipherText);
byte[] Encrypted = DecryptRaw(CiPherBytes, Encoding.UTF8.GetBytes(Key));
return Encoding.UTF8.GetString(Encrypted, 0, Encrypted.Length);
}
}
public class Base64Manager
{
public static byte[] Base64ToByteArray(String base64)
{
return Convert.FromBase64String(base64);
}
public static String ToBase64(byte[] data, Boolean insertLineBreaks = default(Boolean))
{
return insertLineBreaks ? Convert.ToBase64String(data, Base64FormattingOptions.InsertLineBreaks) : Convert.ToBase64String(data);
}
}
public class Program
{
public static void Main()
{
string plainText = "plain text";
string password = "password";
string encrypted = AesManager.EncryptToBase64(plainText, password);
Console.WriteLine(encrypted);
Console.WriteLine(AesManager.DecryptFromBase64(encrypted, password));
Console.ReadLine();
}
}
Android/Java 实现
public enum HashAlgorithm {
SHA512("SHA-512"),
SHA256("SHA-256"),
SHA384("SHA-384"),
SHA1("SHA-1"),
MD5("MD5");
private String Value = "";
HashAlgorithm(String Value) {
this.Value = Value;
}
@Override
public String toString() {
return Value;
}
}
import java.security.MessageDigest;
public class HashManager {
public static byte[] toRawHash(byte[] data,
HashAlgorithm algorithm) throws Exception
{
byte[] buffer = data;
MessageDigest messageDigest = MessageDigest.getInstance(algorithm.toString());
messageDigest.reset();
messageDigest.update(buffer);
return messageDigest.digest();
}
}
Base64Manager 类 Android 实现
import android.util.Base64;
public class Base64Manager {
public static String toBase64(byte[] data,
boolean insertLineBreaks) throws Exception
{
String ret;
if (insertLineBreaks)
{
ret = Base64.encodeToString(data, Base64.DEFAULT);
}
else
{
ret = Base64.encodeToString(data, Base64.NO_WRAP);
}
return ret;
}
public static String toBase64(String data,
boolean insertLineBreaks) throws Exception
{
return toBase64(data.getBytes("UTF-8"), insertLineBreaks);
}
public static byte[] base64ToByteArray(String base64) throws Exception
{
return base64.contains(System.getProperty("line.separator")) ? Base64.decode(base64, Base64.DEFAULT) : Base64.decode(base64, Base64.NO_WRAP);
}
}
Base64Manager 类 Java8+ 实现
import java.util.Base64;
public class Base64Manager {
public static String toBase64(byte[] data, Boolean insertLineBreaks) throws Exception {
String ret;
if (insertLineBreaks) {
ret = Base64.getMimeEncoder().encodeToString(data);
} else {
ret = Base64.getEncoder().encodeToString(data);
}
return ret;
}
public static String toBase64(String data, Boolean insertLineBreaks) throws Exception {
return toBase64(data.getBytes("UTF-8" ), insertLineBreaks);
}
public static byte[] base64ToByteArray(String base64) throws Exception {
return base64.contains(System.getProperty("line.separator")) ? Base64.getMimeDecoder().decode(base64) : Base64.getDecoder().decode(base64);
}
}
import java.security.SecureRandom;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class AesManager {
private static final int MAX_IV_LENGTH = 16;
private static final int MAX_KEY_LENGTH = 32;
public static String decryptFromBase64(String cipherText, String key) throws Exception {
byte[] CiPherBytes = Base64Manager.base64ToByteArray(cipherText);
byte[] KeyBytes = key.getBytes("UTF-8");
return new String((decryptRaw(CiPherBytes, KeyBytes)));
}
public static byte[] generateValidKey(byte[] key) throws Exception {
return Arrays.copyOf(HashManager.toRawHash(key, HashAlgorithm.SHA256), MAX_KEY_LENGTH);
}
public static byte[] decryptRaw(byte[] cipherBytes, byte[] keyBytes) throws Exception {
byte[] IV = Arrays.copyOfRange(cipherBytes, cipherBytes.length - MAX_IV_LENGTH, cipherBytes.length);
byte[] RealBytes = Arrays.copyOf(cipherBytes, cipherBytes.length - MAX_IV_LENGTH);
Cipher AesAlgorithm = Cipher.getInstance("AES/CBC/PKCS5Padding" );
byte[] ValidKeyBytes = generateValidKey(keyBytes);
SecretKeySpec secretKeySpec = new SecretKeySpec(ValidKeyBytes, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(IV);
AesAlgorithm.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] Decrypted = AesAlgorithm.doFinal(RealBytes);
return Decrypted;
}
public static byte[] encryptRaw(byte[] plainBytes, byte[] keyBytes) throws Exception {
Cipher AesAlgorithm = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] ValidKeyBytes = generateValidKey(keyBytes);
SecretKeySpec secretKeySpec = new SecretKeySpec(ValidKeyBytes, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(generateIV());
AesAlgorithm.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] Encrypted = AesAlgorithm.doFinal(plainBytes);
byte[] ret = new byte[Encrypted.length + MAX_IV_LENGTH];
System.arraycopy(Encrypted, 0, ret, 0, Encrypted.length);
System.arraycopy(ivParameterSpec.getIV(), 0, ret, Encrypted.length, MAX_IV_LENGTH);
return ret;
}
private static byte[] generateIV() throws Exception {
return generateRandomArray(MAX_IV_LENGTH);
}
public static byte[] generateRandomArray(int size) {
SecureRandom RandomGenerator = new SecureRandom();
byte[] ret = new byte[size];
RandomGenerator.nextBytes(ret);
return ret;
}
public static String encryptToBase64(String plaintext, String key) throws Exception {
byte[] PlainBytes = plaintext.getBytes("UTF-8");
byte[] KeyBytes = key.getBytes("UTF-8");
return Base64Manager.toBase64(encryptRaw(PlainBytes, KeyBytes), false);
}
}
public class Program {
public static void main(String[] args) throws Exception
{
String plainText = "plain text";
String password = "password";
String encrypted = AesManager.encryptToBase64(plainText, password);
System.out.println(encrypted);
System.out.println(AesManager.decryptFromBase64(encrypted, password));
}
}
输出
Java
PS C:\Users\Megam\OneDrive\Documentos\NetBeansProjects\TestAes\target> java -cp .\TestAes-1.0-SNAPSHOT.jar com.mycompany.testaes.Program
leHBoUoB54bd9JEa9s9INohjVjmb2RZqVzrz2uYEstg=
plain text
PS C:\Users\Megam\OneDrive\Documentos\NetBeansProjects\TestAes\target> java -cp .\TestAes-1.0-SNAPSHOT.jar com.mycompany.testaes.Program
wC6o7cUqZn9KS88L11OuNR2lGDcJ6zBrK1etJEpMHEg=
plain text
PS C:\Users\Megam\OneDrive\Documentos\NetBeansProjects\TestAes\target> java -cp .\TestAes-1.0-SNAPSHOT.jar com.mycompany.testaes.Program
gfM1uVf2a3x6Q/N0XhpDI4svUZx4kTmcl0wkjJfNQrw=
plain text
PS C:\Users\Megam\OneDrive\Documentos\NetBeansProjects\TestAes\target>
点网
PS C:\Users\Megam\source\repos\ConsoleApplication1\ConsoleAppCs\bin\Debug\net5.0> .\ConsoleAppCs.exe
4GTqXhjkh0tXNI6Q4hShSdPPrKcWVEqA5LRBn6fBCH8=
plain text
PS C:\Users\Megam\source\repos\ConsoleApplication1\ConsoleAppCs\bin\Debug\net5.0> .\ConsoleAppCs.exe
aYY1sxre9KfLqkA1XtvN4IwGau6mYInmuvkopFXuKQA=
plain text
PS C:\Users\Megam\source\repos\ConsoleApplication1\ConsoleAppCs\bin\Debug\net5.0> .\ConsoleAppCs.exe
7lesPYAHQxdiCN4Cv5yWyWJlf5pqIukznZzpZTOOFeg=
plain text
PS C:\Users\Megam\source\repos\ConsoleApplication1\ConsoleAppCs\bin\Debug\net5.0>