【问题标题】:How to encrypt text into plain text strings only如何仅将文本加密为纯文本字符串
【发布时间】:2017-05-31 01:13:29
【问题描述】:

我必须在我的程序中实现基本加密。我可以使用被客户端拒绝的 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 是一种编码,而不是一种加密。如果你想要加密字节的明文表示,base64 是一种很好的编码方式。
  • 我知道,我尝试通过编码来获取,但现在我必须进行加密
  • “给定的最终块没有正确填充”
  • 做一些搜索,伙计..

标签: java encryption


【解决方案1】:

所以,基本上你对加密一无所知,并且有你的客户想要加密的问题

好的,快速提示:

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

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

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

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

结果输出可以被解密,但前提是你有相应的秘密

如果您的客户希望您加密某些内容,请确保该内容可以表示为字节...加密字符串...不好...加密已转换为 ... 好的

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

当您决定使用加密/密码时,您必须知道基本上有 2 个不同的组:对称和非对称

对称:解密需要使用相同的密钥(读取密钥)来加密

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

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

非对称密码并非旨在加密大量数据

对称密码用于批量数据

如果您的目标只是在将信息放在硬盘上时对其进行加密,那么您想要的是对称密码

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

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

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

iv 不是秘密,你可以在你的密文前面加上明文信息 iv 需要是密码的一个块的大小,所以在 AES 128 位 = 16 字节的情况下 因此加密时的 IV 是 16 字节(唯一)随机数(意味着您可能不会使用 IV 两次或更多次:保留使用过的 IV,并在获取新的 IV 时,检查它是否已经存储,如果是,则重新开始 IV代,如果没有,存储后使用)

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

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

如果文件必须仅包含可打印文本,则在将字节写入文件之前应用 base16/32/64 之类的编码并在解密之前解码为字节数组(除非您的数据太大,否则您将拥有查找/编写将为您添加/剥离编码的流包装器)

【讨论】:

  • 很好的总结。重要的是要注意,对于使用相同密钥加密的每条消息,IV 必须是唯一且不可预测的。 AES-GCM 本质上是 CTR 模式,使用 Galois 函数提供身份验证标签,使用带有重复 IV/nonce 的 CTR 绝对会破坏安全性。
  • 那是“随机数”的意思,但是是的,我想我应该明确指出这一点
【解决方案2】:

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

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

【讨论】:

  • 客户端不想要编码,他们想要加密,而我对加密一无所知...一旦输入文本文件,我基本上必须加密密码。我把它捡起来,编码并保存回来。稍后使用编码密码。
  • 如果保存密码只是为了检查登录到系统,然后用拉伸和盐对其进行哈希处理,不要加密。如果要保存密码以在不同系统上使用,则需要检索实际密码,然后使用 AES/CBC/PKCS7 对其进行加密,并保存一个单独的 IV 以供每个密码使用。在此处查看有关 AES 的其他答案,并再次询问您是否需要帮助。
【解决方案3】:

您应该对加密内容进行 Base64 处理。顺便说一句,这是通常的技术。

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

【讨论】:

    【解决方案4】:

    问题是填充。我使用了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;
            }
        }    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多