欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java實(shí)現(xiàn)常用的三種加密算法詳解

 更新時間:2022年03月25日 14:15:59   作者:編程碼農(nóng)  
編程中常見的加密算法有以下幾種:信息摘要算法、對稱加密算法以及非對稱加密算法。本文將利用Java實(shí)現(xiàn)這幾種常見的加密算法,需要的可以參考一下

前言

編程中常見的加密算法有以下幾種,它們在不同場景中分別有應(yīng)用。除信息摘要算法外,其它加密方式都會需要密鑰。

  • 信息摘要算法
  • 對稱加密算法
  • 非對稱加密算法

密鑰

密鑰(key,又常稱金鑰)是指某個用來完成加密、解密、完整性驗(yàn)證等密碼學(xué)應(yīng)用的秘密信息。

密鑰分類

  • 加解密中的密鑰:對稱加密中共享相同的密鑰,非對稱加密中分公鑰私鑰,公鑰加密私鑰解密。
  • 消息認(rèn)證碼和數(shù)字簽名中的密鑰:在消息認(rèn)證碼中,消息發(fā)送方和接收方使用共享密鑰進(jìn)行認(rèn)證。在數(shù)字簽名中,簽名使用私鑰,而驗(yàn)證使用公鑰。
  • 會話密鑰和主密鑰:每次通信只使用一次的密鑰稱為會話密鑰(session key)。相對于會話密鑰,重復(fù)使用的密鑰稱為主密鑰(master key)。

密鑰和密碼

密碼一般是由用戶生成,具有可讀性,可以記憶和存儲,常用于軟件管理,而密鑰是供實(shí)現(xiàn)加密算法的軟件使用,不需要具備可讀性(不過在編程中為了方便閱讀都進(jìn)行Base64)。我們也可以通過密碼來生成密鑰。

密鑰管理

  • 生成密鑰:可以用隨機(jī)數(shù)生成密鑰,也可以用口令生成密鑰。
  • 配送密鑰:可采用事先共享密鑰、使用密鑰分配中心、使用公鑰密碼、使用Diffie-Hellman密鑰交換。
  • 更新密鑰
  • 保存密鑰
  • 作廢密鑰

密鑰生成

jdk 中 jce (Java Cryptography Extension) 包含了加密相關(guān)的所有API。

生成對稱加密算法的密鑰

public static SecretKey generateKey(int keySize) {
        KeyGenerator keyGenerator;
        try {
            keyGenerator = KeyGenerator.getInstance("AES");
            keyGenerator.init(keySize);
            return keyGenerator.generateKey();
        } catch (NoSuchAlgorithmException e) {
            // ignore
            return null;
        }
    }

生成對稱非對稱加密算法的密鑰

/**
     * 生成非對稱密鑰對
     *
     * @param keySize 密鑰大小
     * @param random  指定隨機(jī)來源,默認(rèn)使用 JCAUtil.getSecureRandom()
     * @return 非對稱密鑰對
     * @throws NoSuchAlgorithmException NoSuchAlgorithm
     */
    public static PPKeys genKeysRSA(int keySize, SecureRandom random) throws NoSuchAlgorithmException {
        KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
        if (null != random) {
            generator.initialize(keySize, random);
        } else {
            generator.initialize(keySize);
        }
        KeyPair pair = generator.generateKeyPair();
        PPKeys keys = new PPKeys();
        PublicKey publicKey = pair.getPublic();
        PrivateKey privateKey = pair.getPrivate();
        keys.setPublicKey(Base64.getEncoder().encodeToString(publicKey.getEncoded()));
      keys.setPrivateKey(Base64.getEncoder().encodeToString(privateKey.getEncoded()));
        return keys;
    }

密鑰協(xié)商Diffie-Hellman

密鑰協(xié)商是一種協(xié)議,兩方或多方在通過該協(xié)議建立相同的共享密鑰,然后通訊內(nèi)容進(jìn)行對稱加密傳輸,而不需要交換密鑰。

大致過程:每一方生成一個公私鑰對并將公鑰分發(fā)給其它方,當(dāng)都獲得其他方的公鑰副本后就可以離線計(jì)算共享密鑰。

Java中提供了 KeyAgreement 可以實(shí)現(xiàn)密鑰協(xié)商。

  • Alice 和 Bob 分別用他們的私鑰初始化自己的密鑰協(xié)商對象 KeyAgreement ,調(diào)用init() 方法;
  • 然后將通信的每一方的公鑰 傳入執(zhí)行 doPhase(Key key, boolean lastPhase) ;
  • 各方生成共享密鑰 generateSecret()。
public static void diffieHellman() throws Exception {
        AlgorithmParameterGenerator dhParams = AlgorithmParameterGenerator.getInstance("DH");
        dhParams.init(1024);
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH");
        keyGen.initialize(dhParams.generateParameters().getParameterSpec(DHParameterSpec.class), new SecureRandom());

        KeyAgreement aliceKeyAgree = KeyAgreement.getInstance("DH");
        KeyPair alicePair = keyGen.generateKeyPair();
        KeyAgreement bobKeyAgree = KeyAgreement.getInstance("DH");
        KeyPair bobPair = keyGen.generateKeyPair();

        aliceKeyAgree.init(alicePair.getPrivate());
        bobKeyAgree.init(bobPair.getPrivate());

        aliceKeyAgree.doPhase(bobPair.getPublic(), true);
        bobKeyAgree.doPhase(alicePair.getPublic(), true);

       boolean agree = Base64.getEncoder().encodeToString(aliceKeyAgree.generateSecret()).equals(
          Base64.getEncoder().encodeToString(bobKeyAgree.generateSecret())
        );
        System.out.println(agree);
    }

信息摘要算法

信息摘要算法又叫加密散列算法,加密過程不需要密鑰,常見的加密散列算法有MD系列SHA系列

一個理想的加密散列函數(shù)應(yīng)該具備以下特性:

  • 任何信息傳入后,輸出的總是長度固定;
  • 消息摘要看起來是“隨機(jī)的”,這樣根據(jù)原始信息就很難推測出值;
  • 好的散列函數(shù)碰撞概率應(yīng)該極低,也就是不同信息傳入后得到相同值的概率;

MD系列

MD5信息摘要算法(MD5 Message-Digest Algorithm),一種被廣泛使用的加密散列函數(shù),輸出出一個128位(16字節(jié))的散列值(hash value),MD5最初設(shè)計(jì)為加密散列函數(shù),而目前發(fā)現(xiàn)它存在大量漏洞,所以不建議直接用作加密,不過在非加密場景下如:數(shù)據(jù)完整性校驗(yàn),文件完整性校驗(yàn)它仍然有廣泛的應(yīng)用。

public static String md5(String content) {
        try {
            MessageDigest digest = MessageDigest.getInstance("MD5");
            byte[] bytes = digest.digest(content.getBytes(StandardCharsets.UTF_8));
            return Hex.encodeHexString(bytes);
        } catch (final NoSuchAlgorithmException e) {
            throw new IllegalArgumentException(e);
        }
    }

SHA系列

安全散列算法(Secure Hash Algorithm,縮寫為SHA)是一個加密散列函數(shù)家族,是FIPS(美國聯(lián)邦信息處理標(biāo)準(zhǔn))所認(rèn)證的安全散列算法。能計(jì)算出一個數(shù)字消息所對應(yīng)到的,長度固定的字符串(又稱消息摘要)的算法。且若輸入的消息不同,它們對應(yīng)到不同字符串的機(jī)率很高。

它們分別包含 SHA-0、SHA-1、SHA-2、SHA-3,其中 SHA-0、SHA-1 輸出長度是160位,SHA-2 包含 SHA-224、SHA-256、SHA-384、SHA-512、SHA-512/224、SHA-512/256,我們平時常用 SHA-256 。

public static String sha256(String content) {
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256);
            byte[] bytes = digest.digest(content.getBytes(StandardCharsets.UTF_8));
            return Hex.encodeHexString(bytes);
        } catch (final NoSuchAlgorithmException e) {
            throw new IllegalArgumentException(e);
        }
    }

對稱加密算法

對稱加密算法,雙方持有相同密鑰進(jìn)行加解密,常見的對稱加密算法:DES 3DES AES128 AES192 AES256。理解對稱加密需要先明白下面幾個概念:

  • 分組密碼模式:將明文切割進(jìn)行加密,再將密文拼接到一起。比如AES中會將明文數(shù)據(jù)切割為大小16字節(jié)的數(shù)據(jù)塊,最后一塊不夠16字節(jié)時,使用Padding模式進(jìn)行補(bǔ)充。
  • 填充(Padding):它有三種模式PKCS5、PKCS7和NOPADDING,PKCS5用缺少的字節(jié)數(shù)來填充,比如缺少5個字節(jié)就填充5個數(shù)字5,PKCS7缺少的字節(jié)數(shù)用0來填充。如果數(shù)據(jù)剛好是16的整數(shù)倍,PKCS5和PKCS7會再補(bǔ)充一個16字節(jié)數(shù)據(jù)來區(qū)分填充和有效數(shù)據(jù),NOPADDING模式不需要填充。
  • 初始化向量:初始向量IV的作用是使加密更加安全可靠,在分組密碼模式下IV大小對應(yīng)數(shù)據(jù)塊長度。
  • 加密模式:四種加密模式分別是:ECB(電子密碼本模式)、CBC(密碼分組鏈接模式)、CFB、OFB。ECB模式是僅僅使用明文和密鑰來加密數(shù)據(jù),所以該模式下不需要Padding,安全性也較弱,CBC模式數(shù)據(jù)分塊并且使用傳入IV依次進(jìn)行異或操作,安全性也相對較高,所以目前一般都選擇CBC模式。
  • 加密密鑰:不同加密算法密鑰長度不同,比如:DES 默認(rèn)長度56位,3DES默認(rèn)長度168位,也支持128位,AES默認(rèn)128位,也支持192位,256位。我們一般根據(jù)密碼生成密鑰,密碼長度需要滿足算法密鑰長度。

DES

DES 是對稱加密算法領(lǐng)域中的典型算法,因?yàn)槊荑€默認(rèn)長度為56 bit,所以密碼長度需要大于 8 byte,DESKeySpec 取前 8 byte 進(jìn)行密鑰制作。

public static String encryptDES(byte[] content, String password) {
        try {
            SecureRandom random = new SecureRandom();
            DESKeySpec desKeySpec = new DESKeySpec(password.getBytes());
            SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey secretKey = secretKeyFactory.generateSecret(desKeySpec);
            Cipher cipher = Cipher.getInstance("DES");
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, random);
            return Base64.getEncoder().encodeToString(cipher.doFinal(content));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static String decryptDES(String content, String password) throws Exception {
        SecureRandom random = new SecureRandom();
        DESKeySpec desKeySpec = new DESKeySpec(password.getBytes());
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
        Cipher cipher = Cipher.getInstance("DES");
        cipher.init(Cipher.DECRYPT_MODE, secretKey, random);
        return new String(cipher.doFinal(Base64.getDecoder().decode(content)));
    }

3DES

3DES(即Triple DES)。是DES算法的加強(qiáng),它使用3條56位的密鑰對數(shù)據(jù)進(jìn)行三次加密。它以DES為基本模塊,通過組合分組方法設(shè)計(jì)出分組加密算法。比起最初的DES,3DES更為安全。密鑰默認(rèn)長度 168 bit, 密碼需要大于24 byte,IV 是 8 byte 的隨機(jī)數(shù)字和字母數(shù)組。

public static String encrypt3DESECB(String content, String key, String iv) {
        try {
            IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
            DESedeKeySpec dks = new DESedeKeySpec(key.getBytes(StandardCharsets.UTF_8));
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
            SecretKey secretkey = keyFactory.generateSecret(dks);
            Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, secretkey, ivSpec);
            return Base64.getEncoder().encodeToString(cipher.doFinal(content.getBytes(StandardCharsets.UTF_8)));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static String decrypt3DESECB(String content, String key, String iv) {
        try {
            IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
            DESedeKeySpec dks = new DESedeKeySpec(key.getBytes(StandardCharsets.UTF_8));
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
            SecretKey secretkey = keyFactory.generateSecret(dks);
            Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, secretkey, ivSpec);
            return new String(cipher.doFinal(Base64.getDecoder().decode(content)), StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

AES

AES 高級數(shù)據(jù)加密標(biāo)準(zhǔn),能夠有效抵御已知的針對DES算法的所有攻擊,默認(rèn)密鑰長度為128 bit,還可以供選擇 192 bit,256 bit。AES-128 AES-192 AES-256

默認(rèn) AES-128 ,使用 PBEKeySpec 生成固定大小的密鑰。

public static String encryptAES128(String plainText, String password, String salt) throws Exception {
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        byte[] saltBytes = salt.getBytes(StandardCharsets.UTF_8);
        // AES-128 密鑰長度為128bit
        PBEKeySpec spec = new PBEKeySpec(
          password.toCharArray(),
          saltBytes,
          1000,
          128
        );
        SecretKey secretKey = factory.generateSecret(spec);
        SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        AlgorithmParameters params = cipher.getParameters();
        IvParameterSpec iv = params.getParameterSpec(IvParameterSpec.class);

        cipher.init(Cipher.ENCRYPT_MODE, secret, iv);
        byte[] encryptedTextBytes = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));

        String encodedText = Base64.getEncoder().encodeToString(encryptedTextBytes);
        String encodedIV = Base64.getEncoder().encodeToString(iv.getIV());
        String encodedSalt = Base64.getEncoder().encodeToString(saltBytes);
        return encodedSalt + "." + encodedIV + "." + encodedText;
    }


    public static String decryptAES128(String encryptedText, String password) throws Exception {
        String[] fields = encryptedText.split("\\.");
        byte[] saltBytes = Base64.getDecoder().decode(fields[0]);
        byte[] ivBytes = Base64.getDecoder().decode(fields[1]);
        byte[] encryptedTextBytes = Base64.getDecoder().decode(fields[2]);

        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        PBEKeySpec spec = new PBEKeySpec(
          password.toCharArray(),
          saltBytes,
          1000,
          128
        );

        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;
        try {
            decryptedTextBytes = cipher.doFinal(encryptedTextBytes);
            return new String(decryptedTextBytes);
        } catch (IllegalBlockSizeException | BadPaddingException e) {
            throw new RuntimeException(e);
        }
    }

使用 AES-256 時可能會出現(xiàn)下面異常:

java.security.InvalidKeyException: Illegal key size

JDK 1.8.0_161 及以上版本默認(rèn)已經(jīng)啟用無限強(qiáng)度加密:

static {
        java.security.Security.setProperty("crypto.policy", "unlimited");
    }

JDK 1.8.0_161以前版本需要手動安裝 jce 策略文件下載地址

非對稱加密算法

非對稱加密使用一對密鑰,公鑰用作加密,私鑰則用作解密。關(guān)于密鑰大小,截至2020年,公開已知的最大RSA密鑰是破解的是829位的RSA-250,建議至少使用 2048 位密鑰。

public static String encrypt(byte[] publicKey, String plainText) {
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);
        KeyFactory kf;
        try {
            kf = KeyFactory.getInstance("RSA");
            PublicKey publicKeySecret = kf.generatePublic(keySpec);
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.ENCRYPT_MODE, publicKeySecret);
            byte[] encryptedBytes = cipher.doFinal(plainText.getBytes());
            return new String(Base64.getEncoder().encode(encryptedBytes));
        } catch (Exception e) {
            log.error("Rsa encrypt error ", e);
            throw new RuntimeException(e);
        }
    }

    public static String decrypt(byte[] privateKey, String encryptedText) {
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey);
        KeyFactory kf;
        try {
            kf = KeyFactory.getInstance("RSA");
            PrivateKey privateKeySecret = kf.generatePrivate(keySpec);
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.DECRYPT_MODE, privateKeySecret);
            return new String(cipher.doFinal(Base64.getDecoder().decode(encryptedText)), StandardCharsets.UTF_8);
        } catch (Exception e) {
            log.error("Rsa decrypt error ", e);
            throw new RuntimeException(e);
        }
    }

到此這篇關(guān)于Java實(shí)現(xiàn)常用的三種加密算法詳解的文章就介紹到這了,更多相關(guān)Java加密算法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot用JdbcTemplates操作Mysql實(shí)例代碼詳解

    SpringBoot用JdbcTemplates操作Mysql實(shí)例代碼詳解

    JdbcTemplate是Spring框架自帶的對JDBC操作的封裝,目的是提供統(tǒng)一的模板方法使對數(shù)據(jù)庫的操作更加方便、友好,效率也不錯,這篇文章主要介紹了SpringBoot用JdbcTemplates操作Mysql
    2022-10-10
  • mybatis-plus的sql加載順序源碼解析

    mybatis-plus的sql加載順序源碼解析

    這篇文章主要為大家介紹了mybatis-plus的sql加載順序源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • Spring?Boot?2.x升3.x的那些事

    Spring?Boot?2.x升3.x的那些事

    最近項(xiàng)目需求,準(zhǔn)備從Spring Boot 2.x升級到3.x,升級后發(fā)現(xiàn)編譯器報(bào)了一堆錯誤,本文主要介紹了Spring?Boot?2.x升3.x的那些事,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01
  • Spring mvc整合mybatis(crud+分頁插件)操作mysql

    Spring mvc整合mybatis(crud+分頁插件)操作mysql

    這篇文章主要介紹了Spring mvc整合mybatis(crud+分頁插件)操作mysql的步驟詳解,需要的朋友可以參考下
    2017-04-04
  • Java數(shù)據(jù)結(jié)構(gòu)之棧的詳解

    Java數(shù)據(jù)結(jié)構(gòu)之棧的詳解

    這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)之棧簡單操作的相關(guān)資料,需要的朋友可以參考下,希望能夠給你帶來幫助
    2021-09-09
  • Myeclipse清理項(xiàng)目緩存的幾大方法

    Myeclipse清理項(xiàng)目緩存的幾大方法

    今天小編就為大家分享一篇關(guān)于Myeclipse清理項(xiàng)目緩存的幾大方法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • SpringBoot集成內(nèi)存數(shù)據(jù)庫Sqlite的實(shí)踐

    SpringBoot集成內(nèi)存數(shù)據(jù)庫Sqlite的實(shí)踐

    sqlite這樣的內(nèi)存數(shù)據(jù)庫,小巧可愛,做小型服務(wù)端演示程序,非常好用,本文主要介紹了SpringBoot集成Sqlite,具有一定的參考價(jià)值,感興趣的可以了解一下
    2021-09-09
  • 詳解java基于MyBatis使用示例

    詳解java基于MyBatis使用示例

    這篇文章主要介紹了詳解java基于MyBatis使用示例,對學(xué)習(xí)MyBatis有一定的幫助,有需要的可以了解一下。
    2016-11-11
  • TOMCAT內(nèi)存溢出及大小調(diào)整的實(shí)現(xiàn)方法

    TOMCAT內(nèi)存溢出及大小調(diào)整的實(shí)現(xiàn)方法

    下面小編就為大家?guī)硪黄猅OMCAT內(nèi)存溢出及大小調(diào)整的實(shí)現(xiàn)方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-05-05
  • SpringCache緩存自定義配置的實(shí)現(xiàn)

    SpringCache緩存自定義配置的實(shí)現(xiàn)

    本文主要介紹了SpringCache緩存自定義配置的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01

最新評論