简体   繁体   English

使用C#CryptoStream的Java等式对字符串进行加密和解密

[英]Encrypting and Decrypting String using a Java equilavent of the C# CryptoStream

I am looking at developing an application in Java for a mobile platform operating system. 我正在寻找用Java开发用于移动平台操作系统的应用程序。

I have developed an application in C# WPF for the Windows Environment. 我已经在Windows环境的C#WPF中开发了一个应用程序。 I am using a cryptostream in order to encrypt and decrypt a string using the following code. 我正在使用cryptostream以便使用以下代码对字符串进行加密和解密。 the code shown below is the encryption only 下面显示的代码仅是加密

public string encrypt(string encryptionString)
    {
        byte[] clearTextBytes = Encoding.UTF8.GetBytes(encryptionString);

        SymmetricAlgorithm rijn = SymmetricAlgorithm.Create();

        MemoryStream ms = new MemoryStream();
        byte[] rgbIV = Encoding.ASCII.GetBytes("ryojvlzmdalyglrj");
        byte[] key = Encoding.ASCII.GetBytes("hcxilkqbbhczfeultgbskdmaunivmfuo");
        CryptoStream cs = new CryptoStream(ms, rijn.CreateEncryptor(key, rgbIV), CryptoStreamMode.Write);

        cs.Write(clearTextBytes, 0, clearTextBytes.Length);

        cs.Close();

        return Convert.ToBase64String(ms.ToArray());
    }

The encrypted string is stored in an online database. 加密的字符串存储在在线数据库中。 What I need to be able to do is for the java application to be able to read the string from the database and decrypt the string using the same encryption keys from the C# application. 我需要做的是让Java应用程序能够从数据库中读取字符串,并使用来自C#应用程序的相同加密密钥对字符串进行解密。

Thanks for your help. 谢谢你的帮助。

Personally, I like BouncyCastle for Java crypto. 就个人而言,我喜欢Java加密的BouncyCastle This code (using the BouncyCastle lightweight API) should do the trick: 这段代码(使用BouncyCastle轻量级API)应该可以解决问题:

String decrypt(byte[] cryptoBytes, byte[] key, byte[] iv) {
    BlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESEngine()));
    cipher.init(false, new ParametersWithIV(new KeyParameter(key), iv));
    byte[] out = new byte[cipher.getOutputSize(cryptoBytes.length)];
    int offset = cipher.processBytes(cryptoBytes, 0, cryptoBytes.length, out, 0);
    cipher.doFinal(out, offset);
    return new String(out);
}

I find BouncyCastle's lightweight API to be less painful than the JCE provider stuff but you can use it as a provider if you wish. 我发现BouncyCastle的轻量级API比JCE提供程序要痛苦的多,但是您可以根据需要将其用作提供程序。

It looks like both the .net SymmetricAlgorithm and BC's PaddedBufferedBlockCipher default to PKCS7 padding so you should be OK with using the defaults. 看起来.net SymmetricAlgorithm和BC的PaddedBufferedBlockCipher默认为PKCS7填充,因此您可以使用默认值。

You may want to check out javax.crypto.CipherInputStream and javax.crypto.CipherOutputStream. 您可能需要检出javax.crypto.CipherInputStream和javax.crypto.CipherOutputStream。

http://download.oracle.com/javase/1.5.0/docs/api/javax/crypto/CipherInputStream.html http://download.oracle.com/javase/1.5.0/docs/api/javax/crypto/CipherOutputStream.html http://download.oracle.com/javase/1.5.0/docs/api/javax/crypto/CipherInputStream.html http://download.oracle.com/javase/1.5.0/docs/api/javax/crypto /CipherOutputStream.html

They are used almost the exact same way as your sample above, though initialization of the Cipher objects may be slightly different. 尽管Cipher对象的初始化可能略有不同,但它们的使用方式几乎与上述示例完全相同。

I use the following for encrypting between .net and java 我使用以下内容在.net和Java之间进行加密

In .net i use: 在.net中,我使用:

    /// <summary>
    /// DES Encryption method - used to encryp password for the java.
    /// </summary>
    /// <param name="plainText"></param>
    /// <returns></returns>
    public string EncryptData(string plainText)
    {
        DES des = new DESCryptoServiceProvider();
        des.Mode = CipherMode.ECB;
        des.Padding = PaddingMode.PKCS7;

        des.Key = Encoding.UTF8.GetBytes(_secretPhrase.Substring(0, 8));
        des.IV = Encoding.UTF8.GetBytes(_secretPhrase.Substring(0, 8));

        byte[] bytes = Encoding.UTF8.GetBytes(plainText);
        byte[] resultBytes = des.CreateEncryptor().TransformFinalBlock(bytes, 0, bytes.Length);

        return Convert.ToBase64String(resultBytes);
    }

    /// <summary>
    /// DES Decryption method - used the decrypt password encrypted in java
    /// </summary>
    /// <param name="encryptedText"></param>
    /// <returns></returns>
    public string DecryptData(string encryptedText)
    {
        DES des = new DESCryptoServiceProvider();
        des.Mode = CipherMode.ECB;
        des.Padding = PaddingMode.PKCS7;
        des.Key = Encoding.UTF8.GetBytes(_secretPhrase.Substring(0, 8));
        des.IV = System.Text.Encoding.UTF8.GetBytes(_secretPhrase.Substring(0, 8));

        byte[] bytes = Convert.FromBase64String(encryptedText);
        byte[] resultBytes = des.CreateDecryptor().TransformFinalBlock(bytes, 0, bytes.Length);

        return Encoding.UTF8.GetString(resultBytes);
    }

and in java I use: 在Java中,我使用:

public class CryptoUtil { 公共类CryptoUtil {

public static final Logger LOG = Logger.getLogger(CryptoUtil.class);

private Cipher cipher = null;

private SecretKey key = null;

// This variable holds a string based on which a unique key will be generated
private static final String SECRET_PHRASE = "SECRET PHRASE GOES HERE";

// Charset will be used to convert between String and ByteArray
private static final String CHARSET = "UTF8";

 // The algorithm to be used for encryption/decryption DES(Data Encryption Standard)
private static final String ALGORITHM = "DES";

public CryptoUtil() throws DDICryptoException {
    try {
        // generate a key from SecretKeyFactory
        DESKeySpec keySpec = new DESKeySpec(SECRET_PHRASE.getBytes(CHARSET));
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
        key = keyFactory.generateSecret(keySpec);
        cipher = Cipher.getInstance(ALGORITHM);
    } catch (Exception e) {
        LOG.error(e);
        throw new DDICryptoException(e);
    }
}


/**
 * This method takes a plain text string and returns encrypted string using DES algorithm
 * @param plainText
 * @return String
 * @throws DDICryptoException
 */
public String encrypt(String plainText) throws DDICryptoException {
    String encryptedString = null;
    try {
        // initializes the cipher with a key.
        cipher.init(Cipher.ENCRYPT_MODE, key);

        byte[] plainTextAsUTF8 = plainText.getBytes(CHARSET);

        // decrypts data in a single-part or multi-part operation
        byte[] encryptedBytes = cipher.doFinal(plainTextAsUTF8);

        encryptedString = new sun.misc.BASE64Encoder().encode(encryptedBytes);
    } catch (Exception e) {
        LOG.error(e);
        throw new DDICryptoException(e);

    }
    return encryptedString;

}

/**
 * This method takes a plain text string and returns encrypted string using DES algorithm
 * @param encryptedString
 * @return
 * @throws DDICryptoException
 */
public String decrypt(String encryptedString) throws DDICryptoException {    
    String decryptedString = null;
    try {
        byte[] decodedString = new sun.misc.BASE64Decoder().decodeBuffer(encryptedString);

        // initializes the cipher with a key.
        cipher.init(Cipher.DECRYPT_MODE, key);

        // decrypts data in a single-part or multi-part operation
        byte[] decryptedBytes = cipher.doFinal(decodedString);
        decryptedString = new String(decryptedBytes, CHARSET);
    } catch (Exception e) {
        LOG.error(e);
        throw new DDICryptoException(e);
    }
    return decryptedString;
}

} }

I have sort of managed to resolve the problem. 我已经设法解决了这个问题。 The decryption now works fine. 现在解密工作正常。 Using the following code 使用以下代码

    String plainPassword = "";
            try
            {
                SecretKeySpec key = new SecretKeySpec("hcxilkqbbhczfeultgbskdmaunivmfuo".getBytes("US-ASCII"), "AES");

                IvParameterSpec iv = new IvParameterSpec("ryojvlzmdalyglrj".getBytes("US_ASCII"));

                Cipher cipher = Cipher.getInsta

nce("AES/CBC/PKCS7Padding");

            cipher.init(Cipher.DECRYPT_MODE, key, iv);

            byte[] encoded = cipher.doFinal(Base64.decodeBase64(encryptedPassword.getBytes()));
            plainPassword = new String(encoded);
        }
        catch (Exception ex)
        {
            Log.d("Decryption Error", ex.toString());
        }

        return plainPassword;

The problem is now with the encryption. 现在问题出在加密上。 I have used the same code except changed the cipher from decrypt mode to encrypt mode but for some reason when I print out the encrypted string it just prints a load of rubbish that's nothing like the string that C# creates. 我使用了相同的代码,只是将密码从解密模式更改为加密模式,但是由于某些原因,当我打印出加密的字符串时,它只会打印出一些垃圾,与C#创建的字符串完全不同。 Below is teh code for the encryption 以下是用于加密的代码

public String encrypt(String plainPasword)
    {
        String password = "";
        try
        {
            SecretKeySpec key = new SecretKeySpec("hcxilkqbbhczfeultgbskdmaunivmfuo".getBytes("US-ASCII"), "AES");

            IvParameterSpec iv = new IvParameterSpec("ryojvlzmdalyglrj".getBytes("US_ASCII"));

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");

            cipher.init(Cipher.ENCRYPT_MODE, key, iv);

            byte[] encoded = cipher.doFinal(plainPasword.getBytes());
            password = new String(encoded);


        }
        catch (Exception ex)
        {
            Log.d("Encryption Error", ex.toString());
        }
        return password;
    }

What seems to be wrong with this i can't work it out. 这似乎有什么问题,我无法解决。 Thanks 谢谢

        StringBuffer strbuf = new StringBuffer(buf.length * 2);
        int i;

        for (i = 0; i < buf.length; i++) {
            if (((int) buf[i] & 0xff) < 0x10) {
                strbuf.append("0");
            }

            strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
        }

You have to encode the resulting byte array before converting it to string. 您必须对结果字节数组进行编码,然后才能将其转换为字符串。 The code above did the trick for me, while my actual encryption function is below. 上面的代码对我有用,而下面的是我的实际加密功能。

public String encrypt(String data) throws Exception{
    try {
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        Key k = new SecretKeySpec(key.getBytes(), 0, key.length(), "AES");

        // Calculate ciphertext size.
        int blocksize = 16;
        int ciphertextLength = 0;
        int remainder = data.getBytes().length % blocksize;
        if (remainder == 0) {
            ciphertextLength = data.getBytes().length + blocksize;
        } else {
            ciphertextLength = data.getBytes().length - remainder + blocksize;
        }


        cipher.init(Cipher.ENCRYPT_MODE, k);
        byte[] buf = new byte[ciphertextLength];
        cipher.doFinal(data.getBytes(), 0, data.length(), buf, 0);

        StringBuffer strbuf = new StringBuffer(buf.length * 2);
        int i;

        for (i = 0; i < buf.length; i++) {
            if (((int) buf[i] & 0xff) < 0x10) {
                strbuf.append("0");
            }

            strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
        }
        return strbuf.toString();
    } catch (Exception e) {
        Logger.logException(e);
    }
    return null;
}

See Answer #5 on Equivalent to CryptoStream .NET in Java? 请参阅关于Java中的CryptoStream .NET的答案#5

Be sure to read the comments at the bottom... 请务必阅读底部的评论...

KeySpec ks = new DESKeySpec("key12345".getBytes("UTF-8")); SecretKey key = SecretKeyFactory.getInstance("DES").generateSecret(ks);
IvParameterSpec iv = new IvParameterSpec( Hex.decodeHex("1234567890ABCDEF".toCharArray()));
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, key, iv);
byte[] decoded = cipher.doFinal(Base64.decodeBase64("B3xogi/Qfsc="));
System.out.println("Decoded: " + new String(decoded, "UTF-8"));

Hope this helps... 希望这可以帮助...
JK JK

Cemeron, Neat code there! Cemeron,整洁的代码!

I came across an interesting situation where our customer had given the IV the same as the key . 我遇到了一个有趣的情况,我们的客户给IV密码密钥相同。

After trying out various combinations where I was getting bad padding exception, the solution that worked was 在尝试了遇到糟糕的填充异常的各种组合之后,有效的解决方案是

byte[] iv=new byte[8]; // assuming RC2
System.arraycopy(key.getBytes(), 0, iv, 0, key.getBytes().length > iv.length ? key.getBytes().length);

// Now decrypt and hopefully this should work

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM