繁体   English   中英

如何仅将文本加密为纯文本字符串

[英]How to encrypt text into plain text strings only

我必须在程序中实现基本加密。 我可以使用被客户端拒绝的Base64。 所以我正在使用以下方法。 我面临的问题是加密中包含特殊字符,这会导致异常。 我可以更改此代码以某种方式加密为无特殊字符的纯文本。

protected static byte[] encrypt(String text) 
    {
        try
        {
            String key = "6589745268754125";
            // Create key and cipher
            Key aesKey = new SecretKeySpec(key.getBytes(), "AES");
            Cipher cipher = Cipher.getInstance("AES");
            // encrypt the text
            cipher.init(Cipher.ENCRYPT_MODE, aesKey);
            byte[] encrypted = cipher.doFinal(text.getBytes());
            return encrypted;
        }
        catch(Exception ex)
        {
            WriteLog("Encryption Failed");
            WriteLog(ex.getMessage());
            return null;
        }
    }

protected static String decrypt(byte[] pass)
{
    try
    {
        String key = "6589745268754125";
        // Create key and cipher
        Key aesKey = new SecretKeySpec(key.getBytes(), "AES");
        Cipher cipher = Cipher.getInstance("AES");
        // decrypt the text
        cipher.init(Cipher.DECRYPT_MODE, aesKey);           
        String decrypted = new String(cipher.doFinal(pass));        
        return decrypted;
    }
    catch(Exception ex)
    {
        WriteLog("Encryption Failed");      
        WriteLog(ex.getMessage());
        return null;
    }
}

异常消息说“给最终块未正确填充” javax.crypto.BadPaddingException:给定最终块未正确填充

如果客户端不喜欢Base64,请尝试使用Base32或Base16(=十六进制)。 它们是Base64的较不常见但定义明确的替代方案。

您可能还会确切找到客户端不希望您使用Base64的原因。

因此,基本上您对加密一无所知,而您的客户端想要加密

好吧,一个简短的提示:

编码:将输入转换为具有相同信息但又以另一种表示形式的输出...例如:1,2,3-> a,b,c

如您所见,输出看起来不同,但包含相同的信息

请注意,编码/解码不需要任何秘密信息

加密:乍看起来可能很相似,但是这里您需要一些秘密...加密需要2个输入...一个秘密和输入数据

可以解密结果输出,但是只有在您具有相应机密的情况下

如果您的客户希望您加密某些内容,请确保该内容可以表示为字节...加密字符串...不好...加密已转换为<的字符串<在此处插入任意字节编码,例如unicode > ...好

加密通常处理字节(这里我们不在乎历史密码)

当您决定使用加密/密码时,您必须知道实际上有两个不同的组:对称和不对称

symetric:与解密所使用的密钥相同的密钥(读机密)

不对称:存在由公共部分和私有部分(公共/私有密钥)组成的密钥对,公共部分用于加密,私有部分用于解密...除非您需要交换密钥的不同方,否则没有意义

非对称密码通常用于加密解密对称密码的密钥,因为它们很慢,而对称密码通常是快速的

非对称密码不用于加密大量数据

对称密码适用于批量数据

如果您的目标只是在硬盘上放置信息时对其进行加密,则需要使用对称密码

您将需要一个密码来操作密码...并且...您将存在存储密码的问题...因此,如果可以的话,请用户输入足够复杂的密码...请使用密码和具有足够高的迭代计数的函数PBKDF2(足够高=将此数字增加,直到如果仅在启动时才需要此过程,则该过程将花费几秒钟,或者直到您的用户开始抱怨延迟为止)以使用密码来生成二进制密钥。

在GCM模式下将此密钥用于AES(对称密码)

密码将需要称为IV或初始化向量的东西...

iv不是秘密,您可以将此内容作为密文放在前缀之前,因为iv的明文信息iv必须是密码的一个块的大小,因此对于AES 128位= 16字节,因此加密时的IV是16字节(唯一)随机数(表示您不能两次或多次使用IV:保留使用的IV,并在获取新IV时检查它是否已存储;如果是,则重新启动IV代;否则,将其存储然后使用它)

解密时,从文件中读取前置的明文IV(前16个字节)

如果您只想将密文存储在磁盘上,请将其写入二进制文件

如果文件必须仅包含可打印文本,则在将字节写入文件之前应用诸如base16 / 32/64之类的编码,然后在解密之前将其解码为字节数组(除非您的数据太大,那么您将必须查找/写一个将为您添加/添加编码的流包装器)

您应该使用Base64加密内容。 顺便说一下,这是通常的技术。

我猜客户端的问题不是Base64格式本身,而是Base64不是(强)加密的事实。

问题是填充。 我曾经使用AES/CBC/NoPadding并确保我的字符串是16字节的倍数。 因此,除了更改加密和解密之外,我还必须添加两种方法。 一种是在文本的末尾添加\\0即隐式空终止符)以使其为16的倍数,另一种是在解密后将其删除。 所以最终版本是这样的。

public class crypto {

    static String IV = "AAAAAAAAAAAAAAAA";
    static String plaintext = "my non padded text";
    static String encryptionKey = "0123456789abcdef";

    public static void main(String[] args) 
    {
        byte[] cipher = encrypt(plaintext);
        String decrypted = decrypt(cipher);
    }

    protected static String covertto16Byte(String plainText)
    {
        while(plainText.length()%16 != 0)
            plainText += "\0";          
        return plainText;
    }

    protected static String removePadding(String plainText)
    {
        return plainText.replace("\0","");
    }

    protected static byte[] encrypt(String plainText) 
    {
        try 
        {
            String _plaintText_16 = covertto16Byte(plainText);
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE");
            SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), "AES");
            cipher.init(Cipher.ENCRYPT_MODE, key,new IvParameterSpec(IV.getBytes("UTF-8")));
            return cipher.doFinal(_plaintText_16.getBytes("UTF-8"));
        } catch (Exception ex) 
        {
            //catch mechanism
            return null;
        }
    }

    protected static String decrypt(byte[] cipherText) 
    {
        try 
        {
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE");
            SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), "AES");
            cipher.init(Cipher.DECRYPT_MODE, key,new IvParameterSpec(IV.getBytes("UTF-8")));
            return removePadding(new String(cipher.doFinal(cipherText), "UTF-8"));
        } catch (Exception ex) 
        {   
            //catch mechanism
            return null;
        }
    }    
}

暂无
暂无

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

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