java - 如何在 Java 中加密字符串

标签 java encryption

我需要的是加密将显示在 2D 条形码(PDF-417)中的字符串,这样当有人想扫描它时,它将无法读取。

其他要求:

  • 应该不复杂
  • 它不应包含 RSA、PKI 基础设施、 key 对等。

  • 它必须足够简单,才能摆脱四处窥探的人,并且对于有兴趣获取这些数据的其他公司来说也很容易解密。他们调用我们,我们告诉他们标准或给他们一些简单的 key ,然后可以用于解密。

    可能这些公司可以使用不同的技术,因此最好坚持一些与某些特殊平台或技术无关的标准。

    你有什么建议?是否有一些 Java 类在做 encrypt() & decrypt()在实现高安全标准方面没有太多复杂性?

    最佳答案

    This is the first page that shows up via Google and the security vulnerabilities in all the implementations make me cringe so I'm posting this to add information regarding encryption for others as it has been 7 Years from the original post. I hold a Masters Degree in Computer Engineering and spent a lot of time studying and learning Cryptography so I'm throwing my two cents to make the internet a safer place.

    Also, do note that a lot of implementation might be secure for a given situation, but why use those and potentially accidentally make a mistake? Use the strongest tools you have available unless you have a specific reason not to. Overall I highly advise using a library and staying away from the nitty gritty details if you can.

    UPDATE 4/5/18: I rewrote some parts to make them simpler to understand and changed the recommended library from Jasypt to Google's new library Tink, I would recommend completely removing Jasypt from an existing setup.



    前言

    我将在下面概述安全对称加密的基础知识,并指出当人们使用标准 Java 库自行实现加密时我在网上看到的常见错误。如果您只想跳过所有详细信息,请转到 Google's new library Tink将其导入您的项目并使用 AES-GCM 模式进行所有加密,您将是安全的。

    现在,如果您想了解有关如何在 Java 中加密的详细信息,请继续阅读:)

    分组密码

    首先,您需要选择一个对称 key 块密码。块密码是用于创建伪随机性的计算机功能/程序。伪随机性是假随机性,除了量子计算机之外,没有其他计算机能够分辨出它与真实随机性之间的区别。块密码就像密码学的构建块,当与不同的模式或方案一起使用时,我们可以创建加密。

    现在关于今天可用的块密码算法,请确保 从不 , 我再说一遍 从不 使用 DES ,我什至会说永远不要使用 3DES .唯一一个即使是斯诺登的 NSA 版本也能够验证真正尽可能接近伪随机的块密码是 AES 256 .还有 AES 128;区别在于 AES 256 在 256 位块中工作,而 AES 128 在 128 块中工作。总而言之,尽管发现了一些弱点,但 AES 128 被认为是安全的,但 256 仍然很可靠。

    趣闻DES早在 NSA 成立之初就被 NSA 破解了,实际上保密了几年。虽然仍然有人声称3DES是安全的,有不少研究论文发现并分析了3DES中的弱点。 .

    加密模式

    当您采用分组密码并使用特定方案时,就会创建加密,以便将随机性与 key 相结合,以创建只要您知道 key 的可逆事物。这称为加密模式。

    以下是加密模式和最简单的模式 ECB 的示例,以便您可以直观地了解正在发生的事情:

    ECB Mode

    您将在网上最常看到的加密模式如下:

    欧洲央行点击率、CBC、GCM

    在列出的模式之外还存在其他模式,研究人员一直致力于开发新模式以改善现有问题。

    现在让我们继续讨论实现以及什么是安全的。 从不 使用 ECB 这在隐藏重复数据方面很糟糕,如著名的 Linux penguin 所示. Linux Penguin Example

    在Java中实现时,注意如果使用如下代码,默认设置ECB模式:
    Cipher cipher = Cipher.getInstance("AES");
    

    ... 危险 这是一个漏洞! 不幸的是,这在 StackOverflow 和在线教程和示例中随处可见。

    Nonce 和 IV

    为了应对 ECB 模式中发现的问题,创建了也称为 IV 的通知。这个想法是我们生成一个新的随机变量并将其附加到每个加密中,这样当您加密两个相同的消息时,它们就会不同。这背后的美妙之处在于 IV 或随机数是公共(public)知识。这意味着攻击者可以访问它,但只要他们没有您的 key ,他们就无法利用这些知识做任何事情。

    我会看到的常见问题是人们会将 IV 设置为静态值,就像在他们的代码中的固定值一样。当您重复一次时,这就是 IV 的陷阱,您实际上损害了加密的整个安全性。

    生成随机 IV
    SecureRandom randomSecureRandom = SecureRandom.getInstance("SHA1PRNG");
    byte[] iv = new byte[cipher.getBlockSize()];
    randomSecureRandom.nextBytes(iv);
    IvParameterSpec ivParams = new IvParameterSpec(iv);
    

    注: SHA1 已损坏,但我找不到如何将 SHA256 正确实现到此用例中的方法,因此如果有人想对此进行破解并进行更新,那就太棒了!此外,SHA1 攻击仍然是非常规的,因为在一个巨大的集群上可能需要几年时间才能破解。 Check out details here.

    点击率实现

    CTR 模式不需要填充。
     Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
    

    CBC 实现

    如果您选择实现 CBC 模式,请使用 PKCS7Padding 执行以下操作:
     Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
    

    CBC 和 CTR 漏洞以及为什么应该使用 GCM

    尽管 CBC 和 CTR 等其他一些模式是安全的,但它们遇到了攻击者可以翻转加密数据、在解密时更改其值的问题。因此,假设您加密了一条假想的银行消息“Sell 100”,您的加密消息看起来像“eu23ng”,攻击者将一位更改为“eu53ng”,然后在解密您的消息时,它突然读为“Sell 900”。

    为了避免这种情况,大多数互联网使用 GCM,并且每次您看到 HTTPS 时,他们可能都在使用 GCM。 GCM 使用散列对加密消息进行签名,并使用此签名检查以验证消息是否未更改。

    由于其复杂性,我会避免实现 GCM。您最好使用 Googles new library Tink因为在这里,如果你不小心重复了一个 IV,你就会破坏 GCM 案例中的 key ,这是最终的安全漏洞。新的研究人员正在努力开发抗 IV 重复加密模式,即使您重复 IV, key 也不会处于危险之中,但这尚未成为主流。

    现在,如果您确实想实现 GCM,这里是 link to a nice GCM implementation .但是,我无法确保安全性,或者它是否正确实现,但它得到了基础。还要注意 GCM 没有填充。
    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    

    key 与密码

    另一个非常重要的注意事项是,在加密方面, key 和密码不是一回事。密码学中的 key 需要具有一定的熵和随机性才能被认为是安全的。这就是为什么您需要确保使用正确的加密库为您生成 key 。

    所以你真的有两个实现你可以在这里做,第一个是使用在 this StackOverflow thread for Random Key Generation 上找到的代码。 .此解决方案使用安全的随机数生成器从头开始创建您可以使用的 key 。

    另一个不太安全的选项是使用用户输入,例如密码。我们讨论的问题是密码没有足够的熵,所以我们必须使用 PBKDF2 ,一种采用密码并对其进行强化的算法。这是一个 StackOverflow implementation I liked .但是,Google Tink 库内置了所有这些功能,您应该充分利用它。

    Android 开发者

    这里要指出的一个重要点是知道您的 android 代码是可逆向工程的,并且大多数情况下大多数 java 代码也是如此。这意味着如果您在代码中以纯文本形式存储密码。黑客可以轻松地检索它。通常,对于这些类型的加密,您希望使用非对称加密等。这超出了本文的范围,因此我将避免深入探讨。

    interesting reading from 2013 :指出 Android 中 88% 的加密实现是不正确的。

    最后的想法

    我再次建议避免直接为加密实现 java 库并使用 Google Tink ,它会为您省去头疼的麻烦,因为他们在正确实现所有算法方面确实做得很好。即便如此,请确保您检查 Tink github 上提出的问题,到处都弹出漏洞。

    如果您有任何问题或反馈,请随时发表评论!
    安全性总是在变化,您需要尽最大努力跟上它:)

    关于java - 如何在 Java 中加密字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1205135/

    相关文章:

    c - Linux libcrypto AES-128 CBC 加密/解密适用于 Ubuntu,但不适用于 Raspberry Pi

    java - servlet 容器何时会中断我的线程?

    php - 在 PHP 中加密 (mcrypt),在 Ruby 中解密 (OpenSSL::Cipher)

    c# - 如何在 C# 中使用 AES 加密然后在 Perl 上解密?

    Java:实例双数组元素值修改问题

    Java AES 无法解密阿拉伯语

    javascript - 如何在 laravel 中应用客户端密码加密

    java - 检查(使用 openDS SDK)成员属于 openDS LDAP 中的哪个组

    java - RMI客户端和服务器运行在不同的jre版本中

    java - 在 Guice 中绑定(bind) Set<String>