我有一个要求,我必须与之沟通
Web服务通过发送三个加密参数:ID
,key
和initialization vector (IV)
。为此,我需要使用Triple DES (3DES/DESede)
加密以及RSA
加密。执行此操作所需的步骤是:
我获得了一个关于如何执行此操作的C#示例,代码如下所示:
namespace SampleEncryption
{
public class SampleWebServiceInvocation
{
private const string CERT_SUBJECT = "sample.cer";
public string GetReport()
{
ReportService.RService ws = new ReportService.RService();
ReportService.ReportRequest req = new ReportService.ReportRequest();
string key = string.Empty;
string iv = string.Empty;
string id = "1234567890123456";
string encrypt = new CryptEx().EncryptEx(id, CERT_SUBJECT, ref key, ref iv);
req.AccountNumber = encrypt;
req.Key = key;
req.InitializationVector = iv;
ReportService.ReportResponse resp = ws.getReport(req);
if (resp.Success)
return resp.RedirectUrl;
return string.Empty;
}
}
/// <summary>
/// CryptorEx
/// </summary>
public class CryptEx
{
private X509Certificate2 _certificate;
private byte[] _encryptedKey;
private byte[] _encryptedIV;
private byte[] _encryptedText;
private byte[] _decryptedKey;
private byte[] _decryptedIV;
private byte[] _decryptedText;
/// <summary>
/// Default (empty) constructor
/// </summary>
public CryptEx()
{
}
/// <summary>
/// Publicly exposed encrypt method
/// </summary>
public string EncryptEx(string decryptedText, string certSubject, ref string key, ref string iv)
{
string data;
_decryptedText = Convert.FromBase64String(decryptedText);
try
{
_certificate = GetSignerCert(certSubject);
_encryptedText = EncryptWithTripleDES();
EncryptWithRSA();
key = Convert.ToBase64String(_encryptedKey);
iv = Convert.ToBase64String(_encryptedIV);
data = Convert.ToBase64String(_encryptedText);
}
catch (Exception)
{
data = string.Empty;
}
return data;
}
private byte[] EncryptWithTripleDES()
{
//Create a crypto provider for the text
using (TripleDESCryptoServiceProvider tripDes = new TripleDESCryptoServiceProvider())
{
tripDes.Mode = CipherMode.CBC;
ICryptoTransform encryptor = tripDes.CreateEncryptor();
//Encrypt
using (MemoryStream ms = new MemoryStream())
{
CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write);
cs.Write(_decryptedText, 0, _decryptedText.Length);
cs.FlushFinalBlock();
cs.Close();
ms.Close();
_decryptedKey = tripDes.Key;
_decryptedIV = tripDes.IV;
return ms.ToArray();
}
}
}
private void EncryptWithRSA()
{
using (RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)_certificate.PublicKey.Key)
{
_encryptedKey = rsa.Encrypt(_decryptedKey, false);
_encryptedIV = rsa.Encrypt(_decryptedIV, false);
}
}
private static X509Certificate2 GetSignerCert(string certName)
{
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
try
{
store.Open(OpenFlags.ReadOnly);
// First, find certificates that haven't expired
X509Certificate2Collection validCerts = store.Certificates.Find(X509FindType.FindByTimeValid, DateTime.Now, false);
X509Certificate2Collection scorecardCerts = validCerts.Find(X509FindType.FindBySubjectName, certName, false);
if (scorecardCerts.Count == 0)
throw new ApplicationException(string.Format("Unable to find certificate with name of {0}", certName));
if (scorecardCerts.Count > 1)
throw new ApplicationException(string.Format("More than one certificate has a name of {0}\r\n{1}",
certName, GetSubjectNames(scorecardCerts)));
return scorecardCerts[0];
}
finally
{
store.Close();
}
}
private static string GetSubjectNames(X509Certificate2Collection signingCert)
{
StringBuilder sb = new StringBuilder();
foreach (X509Certificate2 cert in signingCert)
sb.AppendLine(cert.Subject);
return sb.ToString();
}
}
}
在我的情况下,我需要在Java中这样做,所以在这里我公开了我的实现的逻辑。
对于Triple DES:
public class DESedeCrypto implements SymmetricCryptoManager {
/**
* Constant for the algorithm being used for Triple DES (CBC)
*/
public static final String DESEDE_CBC_TRANSFORMATION_ALG = "DESede/CBC/NoPadding";
@Override
public DESedeEncryptionResult encrypt(byte[] srcData, String cryptoAlgorithm) throws Exception {
DESedeEncryptionResult result = null;
byte[] encryptedBytes = null;
byte[] initializationVector = null;
if (srcData == null || srcData.length == 0) {
throw new InvalidEncryptionTargetException();
}
KeyGenerator keyGen = KeyGenerator.getInstance("DESede");
SecretKey secretKey = keyGen.generateKey();
Cipher cipher = Cipher.getInstance(cryptoAlgorithm);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
result = new DESedeEncryptionResult();
if (cryptoAlgorithm.equals(DESEDE_CBC_TRANSFORMATION_ALG)) {
IvParameterSpec spec = cipher.getParameters().getParameterSpec(IvParameterSpec.class);
initializationVector = spec.getIV();
result.setInitializationVector(initializationVector);
}
encryptedBytes = cipher.doFinal(srcData);
result.setResultBytes(encryptedBytes);
result.setKeyBytes(secretKey.getEncoded());
return result;
}
}
对于RSA:
public class RSACrypto implements AsymmetricCryptoManager {
/**
* Tranformation algorithm for OAEP.
*/
private static final String OAEP_RSA_TRANSFORMATION = "RSA/ECB/PKCS1Padding";
/**
* Constructor of the class.
*/
public RSACrypto() {
}
@Override
public byte[] encryptWithCertificate(InputStream inputStream, byte[] targetBytes) throws Exception {
byte[] encryptedBytes = null;
if (targetBytes == null || targetBytes.length == 0) {
throw new InvalidEncryptionTargetException();
}
if (inputStream == null) {
throw new InvalidCertificatePathException("Resource specified for operation is not valid");
}
X509Certificate certificate = CryptoUtils.readCertificateFromInputStream(inputStream);
encryptedBytes = getEncryptedBytes(certificate, targetBytes);
return encryptedBytes;
}
private byte[] getEncryptedBytes(X509Certificate certificate, byte[] targetBytes) throws Exception {
byte[] encryptedBytes = null;
PublicKey publicKey = certificate.getPublicKey();
Cipher cipher = Cipher.getInstance(OAEP_RSA_TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
encryptedBytes = cipher.doFinal(targetBytes);
return encryptedBytes;
}
}
以下是我阅读证书的方式:
public static X509Certificate readCertificateFromInputStream(InputStream inputStream) throws Exception {
X509Certificate certificate = null;
CertificateFactory certFactory = CertificateFactory.getInstance(X509_CERT_TYPE);
certificate = (X509Certificate) certFactory.generateCertificate(inputStream);
return certificate;
}
以下是整个加密过程的逻辑:
String base64id = new String(CryptoUtils.encodeBase64(base64id.getBytes()));
DESedeEncryptionResult encryptionResult = desedeCrypto.encrypt(CryptoUtils.decodeBase64(base64id), DESedeCrypto.DESEDE_CBC_TRANSFORMATION_ALG);
byte[] rsaEncryptedKey = rsaCrypto.encryptWithCertificate(certForKeyInputStream, encryptionResult.getKeyBytes());
byte[] rsaEncryptedIv = rsaCrypto.encryptWithCertificate(certForIvInputStream, encryptionResult.getInitializationVector());
String encryptedId = CryptoUtils.getBase64EncodedStr(encryptionResult.getResultBytes());
String finalEncryptedKey = CryptoUtils.getBase64EncodedStr(rsaEncryptedKey);
String finalIv = CryptoUtils.getBase64EncodedStr(rsaEncryptedIv);
用于测试的ID为:1234567890123456
当我将结果发送到Web服务时,我收到一条消息,指出无法进行加密。为了确保,我测试了两种实现(Java和c#)。当我将它们发送到Web服务时,C#生成的值正在工作,但Java实现不起作用。
你知道我是否需要添加到Java实现中的某种特定类型的算法,我的意思是在Triple DES中我们使用DESede / CBC / NoPadding但是c#可能使用另一种算法。 RSA也是如此。
也许有人可以就此给我一些线索或建议?提前谢谢。