密码算法知识也很有意思——聊聊PBE

admin 2024年1月13日16:32:36评论13 views字数 5312阅读17分42秒阅读模式

基于口令的密码算法—PBE实现

PBE介绍

PBE(Password-Based Encryption)是一种基于密码的加密算法,主要用于加密密钥的生成。在Java中,我们可以使用JCE(Java Cryptography Extension)提供的javax.crypto包来实现PBE加密。

考虑一个问题:

我们想要保障重要信息的机密性,用密钥进行加密,那么怎样保证密钥的机密性,用另一个密钥加密,另一个密钥的机密性如何保障呢?

和我们密码口令一样,密码口令要保护网站资产的安全,密码口令如何保管呢,所有网站都是用同一个密码,更不安全,用一个密码保护所有的密码,这个密码我记在脑子里,可以了,这就是keepass、onepass的实现原理。

PBE实现原理

口令做为密钥的一部分,同时增加salt值保护,盐值根据不同的用户可以产生不同的值,这样可以防止适用口令一样产生的加密串是一样的。这样即使一样的加密口令,一样的密钥值,落库时候的加密值也是不一样的。

代码实现

import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import java.security.SecureRandom;
import java.security.spec.KeySpec;
import java.util.Base64;

public class PBEEncryptionExample {

    private static final char[] PASSWORD = "mySecretPassword".toCharArray();
    private static final byte[] SALT = {
            (byte0x00, (byte0x01, (byte0x02, (byte0x03,
            (byte0x04, (byte0x05, (byte0x06, (byte0x07,
    }; //未进行随机化处理
    private static final int ITERATION_COUNT = 1000;

    public static void main(String[] args) throws Exception {
        String plainText = "This is a test message";

        // Encrypt
        byte[] encryptedBytes = encrypt(plainText.getBytes(), PASSWORD, SALT, ITERATION_COUNT);
        System.out.println(Base64.getEncoder().encodeToString(encryptedBytes));

        // Decrypt
        byte[] decryptedBytes = decrypt(encryptedBytes, PASSWORD, SALT, ITERATION_COUNT);
        System.out.println(new String(decryptedBytes));
    }

    private static byte[] encrypt(byte[] plainText, char[] password, byte[] salt, int iterationCount)
            throws Exception {
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
        KeySpec keySpec = new PBEKeySpec(password, salt, iterationCount);
        Cipher pbeCipher = Cipher.getInstance(keyFactory.getAlgorithm());
        pbeCipher.init(Cipher.ENCRYPT_MODE, keyFactory.generateSecret(keySpec), new PBEParameterSpec(salt, iterationCount));
        return pbeCipher.doFinal(plainText);
    }

    private static byte[] decrypt(byte[] cipherText, char[] password, byte[] salt, int iterationCount)
            throws Exception {
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
        KeySpec keySpec = new PBEKeySpec(password, salt, iterationCount);
        Cipher pbeCipher = Cipher.getInstance(keyFactory.getAlgorithm());
        pbeCipher.init(Cipher.DECRYPT_MODE, keyFactory.generateSecret(keySpec), new PBEParameterSpec(salt, iterationCount));
        return pbeCipher.doFinal(cipherText);
    }
}eturn pbeCipher.doFinal(cipherText);
    }
}

输出:

pSqiAUt7url7b7oahPKZOblYOw9UEJna
This is a test message

口令不变,加密出来的数据也是不变的

稍微改改就能实现一个简单版的keepass,比如将明文密码、适用网址生成密文保存起来。适用的时候适用自己的口令完成解密

import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import java.security.SecureRandom;
import java.security.spec.KeySpec;
import java.util.Base64;

public class PBEEncryptionExample {

//    private static final char[] PASSWORD = "Secbh123".toCharArray();
    private static final byte[] SALT = {
            (byte0x00, (byte0x01, (byte0x02, (byte0x03,
            (byte0x04, (byte0x05, (byte0x06, (byte0x07,
    };
    private static final int ITERATION_COUNT = 1000;

    public static void main(String[] args) throws Exception {
//        String plainText = "This is a test message";
        char[] PASSWORD = args[1].toCharArray();
        String plainText = args[0];
        String keyType = args[2];

        // Encrypt
        if (keyType.equals("en")) {
            byte[] encryptedBytes = encrypt(plainText.getBytes(), PASSWORD, SALT, ITERATION_COUNT);
            System.out.println(Base64.getEncoder().encodeToString(encryptedBytes));
        }
        if (keyType.equals("de")) {
            // Decrypt
            byte[] encryptedBytes= Base64.getDecoder().decode(plainText.getBytes());
            byte[] decryptedBytes = decrypt(encryptedBytes, PASSWORD, SALT, ITERATION_COUNT);
            System.out.println(new String(decryptedBytes));
        }
    }

    private static byte[] encrypt(byte[] plainText, char[] password, byte[] salt, int iterationCount)
            throws Exception {
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
        KeySpec keySpec = new PBEKeySpec(password, salt, iterationCount);
        Cipher pbeCipher = Cipher.getInstance(keyFactory.getAlgorithm());
        pbeCipher.init(Cipher.ENCRYPT_MODE, keyFactory.generateSecret(keySpec), new PBEParameterSpec(salt, iterationCount));
        return pbeCipher.doFinal(plainText);
    }

    private static byte[] decrypt(byte[] cipherText, char[] password, byte[] salt, int iterationCount)
            throws Exception {
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
        KeySpec keySpec = new PBEKeySpec(password, salt, iterationCount);
        Cipher pbeCipher = Cipher.getInstance(keyFactory.getAlgorithm());
        pbeCipher.init(Cipher.DECRYPT_MODE, keyFactory.generateSecret(keySpec), new PBEParameterSpec(salt, iterationCount));
        return pbeCipher.doFinal(cipherText);
    }
}

我只要记住自己的口令123,其他密码可以随意落盘了

输出参考:

java PBEEncryptionExample sec 123 en
lQXapDYahhg=

java PBEEncryptionExample lQXapDYahhg= 123 de
sec

原文始发于微信公众号(YY的黑板报):密码算法知识也很有意思——聊聊PBE

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年1月13日16:32:36
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   密码算法知识也很有意思——聊聊PBEhttps://cn-sec.com/archives/2387951.html

发表评论

匿名网友 填写信息