【问题标题】:Encrypt and Decrypt in JavaJava中的加密和解密
【发布时间】:2012-05-05 10:27:00
【问题描述】:

我想将加密密码存储在 Java 文件中。 我看到了一个使用 javax.crypto 的解决方案,但问题在于密钥 是动态生成的,它是随机的。

然后在运行时在 Java 程序中获取并解密此密码。 鉴于我要将已经加密的密码存储在文件中 - 我想获得 解密时正确的文本。

有没有办法告诉javax.crypto方法:

key = KeyGenerator.getInstance(algorithm).generateKey()

这可以用我自己根据某个私钥生成的密钥替换吗?

谁能给我一些关于如何做到这一点的资源?

【问题讨论】:

    标签: java encryption


    【解决方案1】:

    KeyGenerator 用于生成密钥

    您可能需要检查KeySpecSecretKeySecretKeyFactory

    http://docs.oracle.com/javase/1.5.0/docs/api/javax/crypto/spec/package-summary.html

    【讨论】:

    • 谢谢哥们。你能指导我一些如何使用 KeySpec 的例子吗?
    【解决方案2】:

    这是我几个月前制作的样本 该类对数据进行加密和解密

    import java.security.*;
    import java.security.spec.*;
    
    import java.io.*;
    import javax.crypto.*;
    import javax.crypto.spec.*;
    
    public class TestEncryptDecrypt {
    
    private final String ALGO = "DES";
    private final String MODE = "ECB";
    private final String PADDING = "PKCS5Padding";
    private static int mode = 0;
    
    public static void main(String args[]) {
        TestEncryptDecrypt me = new TestEncryptDecrypt();
        if(args.length == 0) mode = 2;
        else mode = Integer.parseInt(args[0]);
        switch (mode) {
        case 0:
            me.encrypt();
            break;
        case 1:
            me.decrypt();
            break;
        default:
            me.encrypt();
            me.decrypt();
        }
    }
    
    public void encrypt() {
    try {
        System.out.println("Start encryption ...");
    
        /* Get Input Data */
        String input = getInputData();
        System.out.println("Input data : "+input);
    
        /* Create Secret Key */
        KeyGenerator keyGen = KeyGenerator.getInstance(ALGO);
        SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
        keyGen.init(56,random);
          Key sharedKey = keyGen.generateKey();
    
        /* Create the Cipher and init it with the secret key */
        Cipher c = Cipher.getInstance(ALGO+"/"+MODE+"/"+PADDING);
        //System.out.println("\n" + c.getProvider().getInfo());
        c.init(Cipher.ENCRYPT_MODE,sharedKey);
        byte[] ciphertext = c.doFinal(input.getBytes());
        System.out.println("Input Encrypted : "+new String(ciphertext,"UTF8"));
    
        /* Save key to a file */
        save(sharedKey.getEncoded(),"shared.key");
    
        /* Save encrypted data to a file */
        save(ciphertext,"encrypted.txt");
    } catch (Exception e) {
        e.printStackTrace();
    }   
    }
    
    public void decrypt() {
    try {
        System.out.println("Start decryption ...");
    
        /* Get encoded shared key from file*/
        byte[] encoded = load("shared.key");
          SecretKeyFactory kf = SecretKeyFactory.getInstance(ALGO);
        KeySpec ks = new DESKeySpec(encoded);
        SecretKey ky = kf.generateSecret(ks);
    
        /* Get encoded data */
        byte[] ciphertext = load("encrypted.txt");
        System.out.println("Encoded data = " + new String(ciphertext,"UTF8"));
    
        /* Create a Cipher object and initialize it with the secret key */
        Cipher c = Cipher.getInstance(ALGO+"/"+MODE+"/"+PADDING);
        c.init(Cipher.DECRYPT_MODE,ky);
    
        /* Update and decrypt */
        byte[] plainText = c.doFinal(ciphertext);
        System.out.println("Plain Text : "+new String(plainText,"UTF8"));
    } catch (Exception e) {
        e.printStackTrace();
    }   
    }
    
    private String getInputData() {
        String id = "owner.id=...";
        String name = "owner.name=...";
        String contact = "owner.contact=...";
        String tel = "owner.tel=...";
        final String rc = System.getProperty("line.separator");
        StringBuffer buf = new StringBuffer();
        buf.append(id);
        buf.append(rc);
        buf.append(name);
        buf.append(rc);
        buf.append(contact);
        buf.append(rc);
        buf.append(tel);
        return buf.toString();
    }
    
    
    private void save(byte[] buf, String file) throws IOException {
          FileOutputStream fos = new FileOutputStream(file);
          fos.write(buf);
          fos.close();
    }
    
    private byte[] load(String file) throws FileNotFoundException, IOException {
        FileInputStream fis = new FileInputStream(file);
        byte[] buf = new byte[fis.available()];
        fis.read(buf);
        fis.close();
        return buf;
    }
    }
    

    【讨论】:

    • -1 您不能将加密文本保存为字符串,因为它可能包含任何字节值,可能无法编码,更重要的是,它们可能无法解码为String。所以上面的代码偶尔会失败
    【解决方案3】:

    这是一个使用 javax.crypto 库和 apache commons 编解码器库进行 Base64 编码和解码的解决方案:

    import java.security.spec.KeySpec;
    import javax.crypto.Cipher;
    import javax.crypto.SecretKey;
    import javax.crypto.SecretKeyFactory;
    import javax.crypto.spec.DESedeKeySpec;
    import org.apache.commons.codec.binary.Base64;
    
    public class TrippleDes {
    
        private static final String UNICODE_FORMAT = "UTF8";
        public static final String DESEDE_ENCRYPTION_SCHEME = "DESede";
        private KeySpec ks;
        private SecretKeyFactory skf;
        private Cipher cipher;
        byte[] arrayBytes;
        private String myEncryptionKey;
        private String myEncryptionScheme;
        SecretKey key;
    
        public TrippleDes() throws Exception {
            myEncryptionKey = "ThisIsSpartaThisIsSparta";
            myEncryptionScheme = DESEDE_ENCRYPTION_SCHEME;
            arrayBytes = myEncryptionKey.getBytes(UNICODE_FORMAT);
            ks = new DESedeKeySpec(arrayBytes);
            skf = SecretKeyFactory.getInstance(myEncryptionScheme);
            cipher = Cipher.getInstance(myEncryptionScheme);
            key = skf.generateSecret(ks);
        }
    
    
        public String encrypt(String unencryptedString) {
            String encryptedString = null;
            try {
                cipher.init(Cipher.ENCRYPT_MODE, key);
                byte[] plainText = unencryptedString.getBytes(UNICODE_FORMAT);
                byte[] encryptedText = cipher.doFinal(plainText);
                encryptedString = new String(Base64.encodeBase64(encryptedText));
            } catch (Exception e) {
                e.printStackTrace();
            }
            return encryptedString;
        }
    
    
        public String decrypt(String encryptedString) {
            String decryptedText=null;
            try {
                cipher.init(Cipher.DECRYPT_MODE, key);
                byte[] encryptedText = Base64.decodeBase64(encryptedString);
                byte[] plainText = cipher.doFinal(encryptedText);
                decryptedText= new String(plainText);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return decryptedText;
        }
    
    
        public static void main(String args []) throws Exception
        {
            TrippleDes td= new TrippleDes();
    
            String target="imparator";
            String encrypted=td.encrypt(target);
            String decrypted=td.decrypt(encrypted);
    
            System.out.println("String To Encrypt: "+ target);
            System.out.println("Encrypted String:" + encrypted);
            System.out.println("Decrypted String:" + decrypted);
    
        }
    
    }
    

    运行上述程序,输出如下:

    String To Encrypt: imparator
    Encrypted String:FdBNaYWfjpWN9eYghMpbRA==
    Decrypted String:imparator
    

    【讨论】:

    • 这个例子对一些加密函数有很大的帮助,但它对其他很多函数都犯了错误。该示例使用String 作为键。此外,它默默地使用了不安全的 ECB 模式加密。也没有真实性或完整性控制。 (字符)编码/解码是可以的,默认填充模式也是如此。 但总的来说,这段代码不安全
    • oneiros 也看看我的问题。 .stackoverflow.com/questions/38007478/…
    • byte[] encryptedText = Base64.decodeBase64((encryptedString); 此行出错。字符串无法转换为字节。
    • 迟了但是为什么要使用 apache commons for Base64。 Java 内置了 base64。
    【解决方案4】:

    对称密钥加密:对称密钥使用相同的密钥进行加密和解密。这种类型的密码学的主要挑战是发送方和接收方之间的密钥交换。

    示例:以下示例使用对称密钥进行加密和解密算法,该算法可作为 Sun 的 JCE(Java Cryptography E扩展)。 Sun JCE 有两层,加密 API 层和提供者层。

    DESData Encryption Standard)是一种流行的对称密钥算法。目前 DES 已经过时并且被认为是不安全的。 三重 DESDES 的更强变体。它是一种对称密钥分组密码。还有其他算法,如 BlowfishTwofishAESA高级E加密S标准)。 AES 是 DES 上的最新加密标准。

    步骤:

    1. 添加安全提供程序:我们使用的是 JDK 提供的 SunJCE 提供程序。
    2. 生成密钥:使用KeyGenerator 和算法生成密钥。我们正在使用DESede
    3. 编码文本:为了跨平台的一致性,使用UTF-8 encoding 将纯文本编码为字节。
    4. 加密文本:ENCRYPT_MODE 实例化Cipher,使用密钥并加密字节。
    5. 解密文本:DECRYPT_MODE 实例化Cipher,使用相同的密钥并解密字节。

    上面给出的所有步骤和概念都是相同的,我们只是替换算法。

    import java.util.Base64;    
    import javax.crypto.Cipher;  
    import javax.crypto.KeyGenerator;   
    import javax.crypto.SecretKey;  
    public class EncryptionDecryptionAES {  
        static Cipher cipher;  
    
        public static void main(String[] args) throws Exception {
            /* 
             create key 
             If we need to generate a new key use a KeyGenerator
             If we have existing plaintext key use a SecretKeyFactory
            */ 
            KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
            keyGenerator.init(128); // block size is 128bits
            SecretKey secretKey = keyGenerator.generateKey();
    
            /*
              Cipher Info
              Algorithm : for the encryption of electronic data
              mode of operation : to avoid repeated blocks encrypt to the same values.
              padding: ensuring messages are the proper length necessary for certain ciphers 
              mode/padding are not used with stream cyphers.  
             */
            cipher = Cipher.getInstance("AES"); //SunJCE provider AES algorithm, mode(optional) and padding schema(optional)  
    
            String plainText = "AES Symmetric Encryption Decryption";
            System.out.println("Plain Text Before Encryption: " + plainText);
    
            String encryptedText = encrypt(plainText, secretKey);
            System.out.println("Encrypted Text After Encryption: " + encryptedText);
    
            String decryptedText = decrypt(encryptedText, secretKey);
            System.out.println("Decrypted Text After Decryption: " + decryptedText);
        }
    
        public static String encrypt(String plainText, SecretKey secretKey)
                throws Exception {
            byte[] plainTextByte = plainText.getBytes();
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
            byte[] encryptedByte = cipher.doFinal(plainTextByte);
            Base64.Encoder encoder = Base64.getEncoder();
            String encryptedText = encoder.encodeToString(encryptedByte);
            return encryptedText;
        }
    
        public static String decrypt(String encryptedText, SecretKey secretKey)
                throws Exception {
            Base64.Decoder decoder = Base64.getDecoder();
            byte[] encryptedTextByte = decoder.decode(encryptedText);
            cipher.init(Cipher.DECRYPT_MODE, secretKey);
            byte[] decryptedByte = cipher.doFinal(encryptedTextByte);
            String decryptedText = new String(decryptedByte);
            return decryptedText;
        }
    }
    

    输出:

    Plain Text Before Encryption: AES Symmetric Encryption Decryption
    Encrypted Text After Encryption: sY6vkQrWRg0fvRzbqSAYxepeBIXg4AySj7Xh3x4vDv8TBTkNiTfca7wW/dxiMMJl
    Decrypted Text After Decryption: AES Symmetric Encryption Decryption
    

    Source

    示例: 密码有两种模式,分别是加密和解密。我们必须在设置模式后每次开始加密或解密文本。

    【讨论】:

      【解决方案5】:
      public class GenerateEncryptedPassword {
      
          public static void main(String[] args){
      
              Scanner sc= new Scanner(System.in);    
              System.out.println("Please enter the password that needs to be encrypted :");
              String input = sc.next();
      
              try {
                  String encryptedPassword= AESencrp.encrypt(input);
                  System.out.println("Encrypted password generated is :"+encryptedPassword);
              } catch (Exception ex) {
                  Logger.getLogger(GenerateEncryptedPassword.class.getName()).log(Level.SEVERE, null, ex);
              }
          }
      }
      

      【讨论】:

        【解决方案6】:

        如果你使用静态密钥,加密和解密总是给出相同的结果;

        public static final String CRYPTOR_KEY = "your static key here";
        byte[] keyByte = Base64.getDecoder().decode(CRYPTOR_KEY);
        key = new SecretKeySpec(keyByte, "AES");
        

        【讨论】:

        • 什么是命名空间?这是 Java 吗?
        • 是的,只是为了使 [SecretKey key;] 静态化。
        【解决方案7】:

        您可能想要使用jasypt 库(Java 简化加密),它非常易于使用。 (另外,建议检查加密密码而不是解密加密密码)

        要使用 jasypt,如果您使用的是 maven,您可以将 jasypt 包含到您的 pom.xml 文件中,如下所示:

        <dependency>
            <groupId>org.jasypt</groupId>
            <artifactId>jasypt</artifactId>
            <version>1.9.3</version>
            <scope>compile</scope>
        </dependency>
        

        然后对密码进行加密,可以使用 StrongPasswordEncryptor

        public static String encryptPassword(String inputPassword) {
            StrongPasswordEncryptor encryptor = new StrongPasswordEncryptor();
            return encryptor.encryptPassword(inputPassword);
        }
        

        注意: 每次调用 encryptPassword 时加密的密码都不一样,但是 checkPassword 方法仍然可以检查未加密的密码是否仍然与每个加密的密码匹配。 p>

        如果要检查未加密的密码和加密的密码,可以使用 checkPassword 方法:

        public static boolean checkPassword(String inputPassword, String encryptedStoredPassword) {
            StrongPasswordEncryptor encryptor = new StrongPasswordEncryptor();
            return encryptor.checkPassword(inputPassword, encryptedStoredPassword);
        }
        

        以下页面提供了有关创建安全加密密码所涉及的复杂性的详细信息。

        http://www.jasypt.org/howtoencryptuserpasswords.html

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-08-05
          • 2022-10-16
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多