Java で AES 暗号化および復号化操作を実行する方法
1. 背景知識
暗号化では、暗号化アルゴリズムは一方向暗号化と双方向暗号化に分類されます。
対称暗号化とは、AES 暗号化、DES 暗号化などを含む、暗号化と復号化に同じキーが使用されることを意味します。
非対称暗号化とは、RSA 暗号化などを含む、暗号化と復号化で異なるキーを使用することを意味します。
一方向暗号化には、MD5 や SHA などの元に戻せないダイジェスト アルゴリズムが含まれます。
双方向暗号化には、対称暗号化と非対称暗号化が含まれます。双方向暗号化は元に戻すことができ、暗号文へのキーが存在します。
2. AES の概要
AES: Advanced Encryption Standard は米国連邦政府によって採用されています A ブロック暗号化現在最も人気のある
対称暗号化アルゴリズム
である標準。
は、DES を置き換えるために使用される新世代のブロック暗号化アルゴリズムです。
AES は、128 ビット、192 ビット、256 ビットの 3 つのキー長をサポートします。
3. AES 暗号化プロセス (AES 処理単位: バイト)
AES の暗号化および復号化プロセスは、ブロック暗号化を介して DES と同じです。
、グループ復号化。いわゆるブロック暗号化とは、暗号化および復号するコンテンツを 128 ビットごとにグループ化し、鍵を 128 ビット、192 ビット、256 ビットごとにグループ化し、グループ化された平文とそれに対応する暗号化および復号化を行うものです。それぞれグループ化されたキー。
暗号化: 平文と鍵がグループ化された後、グループごとに: 平文グループと鍵グループの処理 -> ラウンド鍵の追加 -> 10 ラウンドの暗号化 -> 暗号文グループ
復号化: 各グループ: 暗号文グループ -> ラウンド鍵追加 -> 10 ラウンドの復号化 -> 平文グループ
平文グループ化: 各グループの長さは同じで、両方とも 128 ビット (16 バイト);
キーのグループ化: 128 ビット、192 ビット、および 256 ビットがあります。推奨される暗号化数ラウンド数はそれぞれ 10、12、14 です。
キー グループの処理: 128 ビットのキー グループを例にとります (推奨される暗号化ラウンド数は 10 であり、演算は最初の9回は同じ、10回目は異なる) 同様に、128ビットの鍵もバイト単位の行列で表現され、鍵配列関数により44個の要素の列W[0]が形成され、 W[1]、…、W[43] (各要素は 4 バイト); このうち、W[0]、W[1]、W[2]、W[3] が元のキーで、残りは40 個の要素は 10 のグループに分割され、各グループ 4 要素 (4*4=16 バイト) がそれぞれ 10 ラウンドの暗号化に使用されます。
AES 暗号化アルゴリズムには 4 つの操作が含まれます: バイト置換
(サブバイト)、行シフト
(ShiftRows)、 列混合
(MixColumns) および ラウンド キーと
(AddRoundKey)。
次の図は、AES 暗号化と復号化のプロセスを示しています:
AddRoundKey (ラウンド キーの追加)— 行列内の各単語 各サブキーラウンドキーと XOR 演算され、各サブキーはキー生成スキームによって生成されます。
SubBytes (バイト置換) - 非線形置換関数により、ルックアップ テーブルを使用して各バイトが対応するバイトに置換されます。
ShiftRows (行シフト) — マトリックスの各列を循環的にシフトします。
MixColumns (列の混乱)— マトリックスの各直線行の演算を完全に混合するため。このステップでは、線形変換を使用して各列の 4 バイトをブレンドします。
3 つのパディング モードが含まれます:
NoPadding
: パディングは行われませんが、プレーン テキストはパディングされなければなりません。 be 16 バイトの整数倍。
PKCS5Padding
(デフォルト): 平文ブロックが 16 バイト (128 ビット) 未満の場合、平文ブロックの末尾に対応する文字数を追加します。および各単語セクションの値は、欠落している文字の数に等しくなります。
ISO10126パディング##注※: 平文ブロックが 16 バイト(128 ビット)未満の場合、平文ブロックの末尾に該当するバイト数が追加され、最後の文字値は欠落文字数に等しく、その他の文字は埋められます。乱数。
例: プレーン テキスト: {1,2,3,4,5,a,b,c,d,e}、6 バイトが欠けていても完了する可能性があります{1 ,2,3,4,5,a,b,c,d,e,5,c,3,G,$,6}
4.Java 実装
として
注: AES 暗号化には Base64 暗号化が含まれます##暗号化:
AES 暗号化 -> Base64 暗号化 -> 暗号文復号化:
Base64 復号化 -> AES 復号化 -> プレーン テキストテスト アドレス: ここをクリック
4.1 キーとオフセットの生成
大文字と小文字と数字の 16 個の乱数を生成します:
private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; // 数字和26个字母组成 private static final Random RANDOM = new SecureRandom(); /** * 获取长度为 6 的随机字母+数字 * @return 随机数字 */ public static String getRandomNumber() { char[] nonceChars = new char[16]; //指定长度为6位/自己可以要求设置 for (int index = 0; index < nonceChars.length; ++index) { nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length())); } return new String(nonceChars); }
4.2 AESUtil.java ソース コード
import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.Base64Utils; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; /** * AES加密工具类 * * @author ACGkaka * @since 2021-06-18 19:11:03 */ public class AESUtil { /** * 日志相关 */ private static final Logger LOGGER = LoggerFactory.getLogger(AESUtil.class); /** * 编码 */ private static final String ENCODING = "UTF-8"; /** * 算法定义 */ private static final String AES_ALGORITHM = "AES"; /** * 指定填充方式 */ private static final String CIPHER_PADDING = "AES/ECB/PKCS5Padding"; private static final String CIPHER_CBC_PADDING = "AES/CBC/PKCS5Padding"; /** * 偏移量(CBC中使用,增强加密算法强度) */ private static final String IV_SEED = "1234567812345678"; /** * AES加密 * @param content 待加密内容 * @param aesKey 密码 * @return */ public static String encrypt(String content, String aesKey){ if(StringUtils.isBlank(content)){ LOGGER.info("AES encrypt: the content is null!"); return null; } //判断秘钥是否为16位 if(StringUtils.isNotBlank(aesKey) && aesKey.length() == 16){ try { //对密码进行编码 byte[] bytes = aesKey.getBytes(ENCODING); //设置加密算法,生成秘钥 SecretKeySpec skeySpec = new SecretKeySpec(bytes, AES_ALGORITHM); // "算法/模式/补码方式" Cipher cipher = Cipher.getInstance(CIPHER_PADDING); //选择加密 cipher.init(Cipher.ENCRYPT_MODE, skeySpec); //根据待加密内容生成字节数组 byte[] encrypted = cipher.doFinal(content.getBytes(ENCODING)); //返回base64字符串 return Base64Utils.encodeToString(encrypted); } catch (Exception e) { LOGGER.info("AES encrypt exception:" + e.getMessage()); throw new RuntimeException(e); } }else { LOGGER.info("AES encrypt: the aesKey is null or error!"); return null; } } /** * 解密 * * @param content 待解密内容 * @param aesKey 密码 * @return */ public static String decrypt(String content, String aesKey){ if(StringUtils.isBlank(content)){ LOGGER.info("AES decrypt: the content is null!"); return null; } //判断秘钥是否为16位 if(StringUtils.isNotBlank(aesKey) && aesKey.length() == 16){ try { //对密码进行编码 byte[] bytes = aesKey.getBytes(ENCODING); //设置解密算法,生成秘钥 SecretKeySpec skeySpec = new SecretKeySpec(bytes, AES_ALGORITHM); // "算法/模式/补码方式" Cipher cipher = Cipher.getInstance(CIPHER_PADDING); //选择解密 cipher.init(Cipher.DECRYPT_MODE, skeySpec); //先进行Base64解码 byte[] decodeBase64 = Base64Utils.decodeFromString(content); //根据待解密内容进行解密 byte[] decrypted = cipher.doFinal(decodeBase64); //将字节数组转成字符串 return new String(decrypted, ENCODING); } catch (Exception e) { LOGGER.info("AES decrypt exception:" + e.getMessage()); throw new RuntimeException(e); } }else { LOGGER.info("AES decrypt: the aesKey is null or error!"); return null; } } /** * AES_CBC加密 * * @param content 待加密内容 * @param aesKey 密码 * @return */ public static String encryptCBC(String content, String aesKey){ if(StringUtils.isBlank(content)){ LOGGER.info("AES_CBC encrypt: the content is null!"); return null; } //判断秘钥是否为16位 if(StringUtils.isNotBlank(aesKey) && aesKey.length() == 16){ try { //对密码进行编码 byte[] bytes = aesKey.getBytes(ENCODING); //设置加密算法,生成秘钥 SecretKeySpec skeySpec = new SecretKeySpec(bytes, AES_ALGORITHM); // "算法/模式/补码方式" Cipher cipher = Cipher.getInstance(CIPHER_CBC_PADDING); //偏移 IvParameterSpec iv = new IvParameterSpec(IV_SEED.getBytes(ENCODING)); //选择加密 cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv); //根据待加密内容生成字节数组 byte[] encrypted = cipher.doFinal(content.getBytes(ENCODING)); //返回base64字符串 return Base64Utils.encodeToString(encrypted); } catch (Exception e) { LOGGER.info("AES_CBC encrypt exception:" + e.getMessage()); throw new RuntimeException(e); } }else { LOGGER.info("AES_CBC encrypt: the aesKey is null or error!"); return null; } } /** * AES_CBC解密 * * @param content 待解密内容 * @param aesKey 密码 * @return */ public static String decryptCBC(String content, String aesKey){ if(StringUtils.isBlank(content)){ LOGGER.info("AES_CBC decrypt: the content is null!"); return null; } //判断秘钥是否为16位 if(StringUtils.isNotBlank(aesKey) && aesKey.length() == 16){ try { //对密码进行编码 byte[] bytes = aesKey.getBytes(ENCODING); //设置解密算法,生成秘钥 SecretKeySpec skeySpec = new SecretKeySpec(bytes, AES_ALGORITHM); //偏移 IvParameterSpec iv = new IvParameterSpec(IV_SEED.getBytes(ENCODING)); // "算法/模式/补码方式" Cipher cipher = Cipher.getInstance(CIPHER_CBC_PADDING); //选择解密 cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv); //先进行Base64解码 byte[] decodeBase64 = Base64Utils.decodeFromString(content); //根据待解密内容进行解密 byte[] decrypted = cipher.doFinal(decodeBase64); //将字节数组转成字符串 return new String(decrypted, ENCODING); } catch (Exception e) { LOGGER.info("AES_CBC decrypt exception:" + e.getMessage()); throw new RuntimeException(e); } }else { LOGGER.info("AES_CBC decrypt: the aesKey is null or error!"); return null; } } public static void main(String[] args) { // AES支持三种长度的密钥:128位、192位、256位。 // 代码中这种就是128位的加密密钥,16字节 * 8位/字节 = 128位。 String random = RandomStringUtils.random(16, "abcdefghijklmnopqrstuvwxyz1234567890"); System.out.println("随机key:" + random); System.out.println(); System.out.println("---------加密---------"); String aesResult = encrypt("测试AES加密12", random); System.out.println("aes加密结果:" + aesResult); System.out.println(); System.out.println("---------解密---------"); String decrypt = decrypt(aesResult, random); System.out.println("aes解密结果:" + decrypt); System.out.println(); System.out.println("--------AES_CBC加密解密---------"); String cbcResult = encryptCBC("测试AES加密12456", random); System.out.println("aes_cbc加密结果:" + cbcResult); System.out.println(); System.out.println("---------解密CBC---------"); String cbcDecrypt = decryptCBC(cbcResult, random); System.out.println("aes解密结果:" + cbcDecrypt); System.out.println(); } }
4.3実行結果
随机key:golrtt58318fx7ol ---------加密--------- aes加密结果:Xy8W9lCeVue9Ao36z+duM7D7WeS5tdBihIMb1q9KpNg= ---------解密--------- aes解密结果:测试AES加密12 --------AES_CBC加密解密--------- aes_cbc加密结果:xs3ypQXyd62P9jB0+RvOqxFnHIHBIlVdqoZLuqYNBLw= ---------解密CBC--------- aes解密结果:测试AES加密12456
4.4 オンライン検証
以上がJava で AES 暗号化および復号化操作を実行する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









Java の Weka へのガイド。ここでは、weka java の概要、使い方、プラットフォームの種類、利点について例を交えて説明します。

この記事では、Java Spring の面接で最もよく聞かれる質問とその詳細な回答をまとめました。面接を突破できるように。

Java 8は、Stream APIを導入し、データ収集を処理する強力で表現力のある方法を提供します。ただし、ストリームを使用する際の一般的な質問は次のとおりです。 従来のループにより、早期の中断やリターンが可能になりますが、StreamのForeachメソッドはこの方法を直接サポートしていません。この記事では、理由を説明し、ストリーム処理システムに早期終了を実装するための代替方法を調査します。 さらに読み取り:JavaストリームAPIの改善 ストリームを理解してください Foreachメソッドは、ストリーム内の各要素で1つの操作を実行する端末操作です。その設計意図はです

Java での日付までのタイムスタンプに関するガイド。ここでは、Java でタイムスタンプを日付に変換する方法とその概要について、例とともに説明します。

カプセルは3次元の幾何学的図形で、両端にシリンダーと半球で構成されています。カプセルの体積は、シリンダーの体積と両端に半球の体積を追加することで計算できます。このチュートリアルでは、さまざまな方法を使用して、Javaの特定のカプセルの体積を計算する方法について説明します。 カプセルボリュームフォーミュラ カプセルボリュームの式は次のとおりです。 カプセル体積=円筒形の体積2つの半球体積 で、 R:半球の半径。 H:シリンダーの高さ(半球を除く)。 例1 入力 RADIUS = 5ユニット 高さ= 10単位 出力 ボリューム= 1570.8立方ユニット 説明する 式を使用してボリュームを計算します。 ボリューム=π×R2×H(4

Spring Bootは、Java開発に革命をもたらす堅牢でスケーラブルな、生産対応のJavaアプリケーションの作成を簡素化します。 スプリングエコシステムに固有の「構成に関する慣習」アプローチは、手動のセットアップを最小化します。
