草庐IT

Java AES加解密静态秘钥

coder 2024-04-01 原文

我有一个应用程序需要在配置文件中存储一些 secret 密码,例如数据库和 ftp 密码/详细信息。我环顾四周,发现了很多使用 AES 的加密/解密解决方案,但我似乎无法弄清楚如何在不更改 key 的情况下使其工作。这意味着我可以加密和解密(使用相同的 SecretKey),但要在重启等过程中保持持久性。我似乎无法让 SecretKey 保持不变。下面的例子展示了我的方法:

String secret = Encryptor.encrpytString("This is secret");
String test = Encryptor.decrpytString(secret);
System.out.println(test); //This is secret is printed

到目前为止一切顺利。但是,如果我运行一次它,我可能会得到 '2Vhht/L80UlQ184S3rlAWw==' 的值作为我的 secret ,下一次它是 'MeC4zCf9S5wUUKAu8rvpCQ==',所以大概 key 正在改变。我假设我正在对这个问题应用一些反直觉的逻辑,如果有人能阐明 a) 我做错了什么,或者 b) 一个允许我存储加密密码信息的解决方案,我将不胜感激并可使用所提供的信息进行检索。

我的方法如下:

private static final String salt = "SaltySalt";

private static byte [] ivBytes = null;

private static byte[] getSaltBytes() throws Exception {
    return salt.getBytes("UTF-8");
}

private static char[] getMasterPassword() {
    return "SuperSecretPassword".toCharArray();
}

private static byte[] getIvBytes() throws Exception {
    if (ivBytes == null) {
        //I don't have the parameters, so I'll generate a dummy encryption to create them
        encrpytString("test");
    }
    return ivBytes;
}

public static String encrpytString (String input) throws Exception {
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    PBEKeySpec spec = new PBEKeySpec(getMasterPassword(), getSaltBytes(), 65536,256);
    SecretKey secretKey = factory.generateSecret(spec);
    SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, secret);
    ivBytes = cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
    byte[] encryptedTextBytes = cipher.doFinal(input.getBytes("UTF-8"));
    return DatatypeConverter.printBase64Binary(encryptedTextBytes);        
}

public static String decrpytString (String input) throws Exception {
    byte[] encryptedTextBytes = DatatypeConverter.parseBase64Binary(input);
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    PBEKeySpec spec = new PBEKeySpec(getMasterPassword(), getSaltBytes(), 65536, 256);
    SecretKey secretKey = factory.generateSecret(spec);
    SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(getIvBytes()));
    byte[] decryptedTextBytes = cipher.doFinal(encryptedTextBytes);
    return new String(decryptedTextBytes);
}

感谢您的帮助!

最佳答案

好的,看来我已经找到问题的答案了。我的信息来自 this Stackoverflow post . 据我了解,IV(初始化 vector )用于将熵添加到加密过程中。每次创建新密码时,Java 都会创建略有不同的 IV。因此有两种解决方案:

  1. 使用固定的 IV,或者
  2. 将 IV 与加密数据一起存储。

根据我的阅读,选项 1 不是很好的做法;所以选项2是。我知道应该可以简单地将 IV 附加到加密字符串(因为仍然需要 secret ),因此在解密时可以重建 IV。

这是几乎完整的解决方案。我在解密时仍然遇到一些填充错误(请参阅我的评论)。我现在没有时间花在这上面,所以作为临时措施,我立即尝试解密加密的字符串并继续尝试(迭代)直到它起作用。它似乎有大约 50% 的命中率 + 我没有经常加密,以至于它成为一个性能问题。如果有人可以提出修复建议(只是为了完整起见),那就太好了。

private static final String salt = "SaltySalt";

private static final int IV_LENGTH = 16;

private static byte[] getSaltBytes() throws Exception {
    return salt.getBytes("UTF-8");
}

private static char[] getMasterPassword() {
    return "SuperSecretPassword".toCharArray();
}

public static String encrpytString (String input) throws Exception {
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    PBEKeySpec spec = new PBEKeySpec(getMasterPassword(), getSaltBytes(), 65536,256);
    SecretKey secretKey = factory.generateSecret(spec);
    SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, secret);
    byte[] ivBytes = cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
    byte[] encryptedTextBytes = cipher.doFinal(input.getBytes("UTF-8"));
    byte[] finalByteArray = new byte[ivBytes.length + encryptedTextBytes.length]; 
    System.arraycopy(ivBytes, 0, finalByteArray, 0, ivBytes.length);
    System.arraycopy(encryptedTextBytes, 0, finalByteArray, ivBytes.length, encryptedTextBytes.length);
    return DatatypeConverter.printBase64Binary(finalByteArray);        
}

public static String decrpytString (String input) throws Exception {
    if (input.length() <= IV_LENGTH) {
        throw new Exception("The input string is not long enough to contain the initialisation bytes and data.");
    }
    byte[] byteArray = DatatypeConverter.parseBase64Binary(input);
    byte[] ivBytes = new byte[IV_LENGTH];
    System.arraycopy(byteArray, 0, ivBytes, 0, 16);
    byte[] encryptedTextBytes = new byte[byteArray.length - ivBytes.length];
    System.arraycopy(byteArray, IV_LENGTH, encryptedTextBytes, 0, encryptedTextBytes.length);
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    PBEKeySpec spec = new PBEKeySpec(getMasterPassword(), getSaltBytes(), 65536, 256);
    SecretKey secretKey = factory.generateSecret(spec);
    SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(ivBytes));
    byte[] decryptedTextBytes = cipher.doFinal(encryptedTextBytes);
    return new String(decryptedTextBytes);
}

关于Java AES加解密静态秘钥,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31238352/

有关Java AES加解密静态秘钥的更多相关文章

  1. 区块链之加解密算法&数字证书 - 2

    目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非

  2. ruby - Ruby 中的单 block AES 解密 - 2

    我需要尝试一些AES片段。我有一些密文c和一个keyk。密文已使用AES-CBC加密,并在前面加上IV。不存在填充,纯文本的长度是16的倍数。所以我这样做:aes=OpenSSL::Cipher::Cipher.new("AES-128-CCB")aes.decryptaes.key=kaes.iv=c[0..15]aes.update(c[16..63])+aes.final它工作得很好。现在我需要手动执行CBC模式,所以我需要单个block的“普通”AES解密。我正在尝试这个:aes=OpenSSL::Cipher::Cipher.new("AES-128-ECB")aes.dec

  3. ruby-on-rails - 我如何比较 'Bcrypt' Gem解密的密码和加密的密码 - 2

    我正在尝试对某些帖子的评论使用简单的身份验证。用户使用即时ID和密码输入评论我使用“bcrypt”gem将密码存储在数据库中。在comments_controller.rb中像这样@comment=Comment.new(comment_params)bcrypted_pwd=BCrypt::Password.create(@comment.user_pwd)@comment.user_pwd=bcrypted_pwd当用户想要删除他们的评论时,我使用data-confirm-modalgem来确认数据在这部分,我必须解密用户输入的密码以与数据库中的加密密码进行比较我怎样才能解密密码,

  4. ruby - 如何在 Ruby 中只执行一次方法?有静态变量吗? - 2

    我写了一个脚本,其中包含一些方法定义,没有类和一些公共(public)代码。其中一些方法执行一些非常耗时的shell程序。然而,这些shell程序只需要在第一次调用该方法时执行。现在在C中,我会在每个方法中声明一个静态变量,以确保这些程序只执行一次。我怎么能在Ruby中做到这一点? 最佳答案 ruby中有一个成语:x||=y。defsomething@something||=calculate_somethingendprivatedefcalculate_something#somelongprocessend但是如果您的“长时间

  5. ruby-on-rails - Ruby 中的类方法(相当于 JAVA 中的静态方法) - 2

    伙计们,我正在学习ruby​​,最近从JAVA转行。在JAVA中,我可以将类的成员变量设为静态,并且该成员变量在类的实例中保持不变。我如何在ruby​​中实现相同的目标。我在我的ruby课上做了这样的事情:classBaseclass@@wordshashend到目前为止,这似乎在我测试时达到了目的,即@@wordhash在Baseclass的实例中保持不变。我的理解对吗?另外,我想在类中有一个成员方法,相当于JAVA中的静态方法(我不需要类的实例来访问它)。我怎样才能做到这一点?例如,我想在Baseclass中有一个像getwordshash()这样的方法,它返回@@wordshas

  6. ruby - 如何让模块 mixins 为静态方法工作? - 2

    假设我有两个模块。是否可以将一个模块包含在另一个模块中,使其表现得像一个混入?例如:moduleAdefself.fooputs"foo"barendendmoduleBincludeAdefself.barputs"bar"endendB.barB.foo编辑:我意识到我最初把代码抄错了。这些方法需要是静态的。更正后的代码在上面(但不起作用)。 最佳答案 如您所知,它不起作用,但为什么它不起作用是关于Ruby对象模型的非常好的一课。当你创建一个对象的实例时,你创建的是一个新对象,它有一组实例变量和一个指向对象类的指针(以及一些其他

  7. ruby - ruby 中的错误解密错误 - 2

    在执行cipher.final时,提示baddecrypt错误。我试图找出问题所在。但是,我找不到。你能告诉我我的代码有什么问题吗?这是我的代码:require'openssl'require'base64'require'hex_string'result_h="4fcd6b1ac843a2f8bf13f2e53dd5c1544fcd6b1ac843a2f8"key=result_h.to_byte_stringencrypt_str="79994A6EF73DA76C";cipher=OpenSSL::Cipher.new("DES-EDE3-CBC")cipher.decrypt

  8. ruby-on-rails - Heroku Cedar - 没有安装 Resque 前端的静态 Assets - 2

    我有一个简单的Rails应用程序部署到HerokuCedar堆栈。该应用程序使用Resque并安装了ResqueSinatra前端应用程序,因此我可以监控队列:#routes.rb...mountResque::Server,:at=>"/resque"这很好用,但是当部署到Heroku时,Resquefront-end'sCSS&JavaScript没有被送达。一段Heroku的日志表明它正在返回零字节:...2011-07-13T16:19:35+00:00heroku[router]:GETmyapp.herokuapp.com/resque/style.cssdyno=web.

  9. ruby-on-rails - 配置非静态路由 - 2

    我不知道如何在Rails3.0中执行此操作。我有一个Controllerproducts和一个操作search,我在routes.rb中尝试过resources:products,:collection=>{:search=>:post}和match'products/search'=>'products#search',:via=>[:get,:post]和许多其他设置,但每当我访问products/search时,我仍然会收到错误消息,提示无法找到ID为search的产品Action显示。有人知道我做错了什么吗?谢谢。 最佳答案

  10. ruby-on-rails - rails 加密/解密 - 2

    我需要在我的Rails应用程序中进行加密和解密。我正在尝试使用ezcrypto,但每当我进行解密时,我都会收到此错误。OpenSSL::Cipher::CipherErrorinProfilesController#showwrongfinalblocklength需要更改什么才能停止此错误。我尝试像这样使用openssl的另一个实现(从我的模型中调用的方法)defencrypt_attr(unencrypted)c=OpenSSL::Cipher.new("aes-256-cbc")c.encryptc.key=Digest::SHA1.hexdigest('pass')e=c.up

随机推荐