Web Service的值的3DES和RSA加密在C#中工作,但在Java中不起作用

时间:2017-11-15 14:38:44

标签: java c# encryption rsa tripledes

我有一个要求,我必须与之沟通 Web服务通过发送三个加密参数:IDkeyinitialization vector (IV)。为此,我需要使用Triple DES (3DES/DESede)加密以及RSA加密。执行此操作所需的步骤是:

  1. 以明文开头。将ID从base64字符串解码为字节数组。原始ID不是base64编码,但必须执行此步骤。
  2. 使用3DES加密base64解码的ID并生成密钥和IV
  3. 加密使用RSA生成的密钥和IV(使用提供的证书)
    1. 将加密ID,加密密钥和IV转换为base64字符串。
  4. 我获得了一个关于如何执行此操作的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也是如此。

    也许有人可以就此给我一些线索或建议?提前谢谢。

0 个答案:

没有答案