blog

セキュリティ・シリーズ - 手書きJAVA暗号化、復号化

ソフトウェアの暗号化と復号化は、暗号技術、プログラミング言語、オペレーティング・システム、データ構造など、ほとんどすべてのコンピュータ技術と密接に統合できる魅力的な研究分野です。そして、ある理由から、...

Aug 13, 2020 · 6 min. read
シェア

ソフトウェアの暗号化と復号化は、暗号技術、プログラミング言語、オペレーティング・システム、データ構造など、ほとんどすべてのコンピュータ技術と密接に統合できる魅力的な研究分野です。ある理由から、この分野への関心は低いレベルにとどまっています。

ネットワーク・セキュリティでは、一般に次のようなポイントに注意する必要があります:

  • 完全性: 情報が転送中に改ざんされていないことを保証すること。

  • プライバシー:暗号化により、信頼できるエンティティだけが情報を見ることができるようにすること。

  • 送信元認証:メッセージを送信したのが、なりすましの送信元ではなく、信頼できる送信元であることを保証します。

  • 否認防止:このメッセージが送信されたことを後から否定することができないこと。

今日はデータ伝送のプライバシーについてお話します。暗号化は最も一般的なセキュリティと機密性の手段であり、技術的な手段を用いて重要なデータを文字化けした伝送に変え、目的地に到達した後は同じか異なる手段で復元します。

暗号化は、アルゴリズムと鍵という2つの要素で構成されています。

I.異なる暗号化アルゴリズムと復号化アルゴリズムを用いた暗号化と復号化。

暗号化と復号化の簡単な例から始めましょう。

package com.wuxiaolong.EncrypteDecrypt;
import org.apache.commons.codec.digest.DigestUtils;
/**
 * Description:
 *
 * 
 * @date 
 */
public class Test1 {
 public static void main(String[] args) {
 String content = "愛してる。";
 Integer key = 1000;
 // ユーザーAがメッセージを送信する前に、何らかの方法で暗号化されている。
 String encryptStr = xor(content,key);
 System.out.println(encryptStr);
 // 暗号文はネットワーク経由で送信される
 // ユーザBは暗号文を受け取り、同じ方法で復号する。
 String decryptStr = xor(encryptStr,key);
 System.out.println(decryptStr);
 }
 /**
 * 暗号化アルゴリズムと秘密鍵
 * @param content
 * @return
 */
 public static String xor(String content, Integer key){
 char[] chars = content.toCharArray();
 for(int i=0; i<chars.length; i++){
 chars[i] = (char) (chars[i]^key) ;
 }
 return new String(chars);
 }
}

ここでは、カスタムの暗号化と復号化メソッドxorを使用します。このメソッドは、2つのパラメータを受け取り、1つは元のコンテンツ、秘密鍵のキーです。

実行結果。

懹䲈 //暗号化結果 I love you //復号化結果

第二に、異種分散暗号化と復号化の原理を説明します。

メッセージを送信する前に、アルゴリズム+秘密鍵を使って送信メッセージを暗号化し、暗号化して暗号文を使ってネットワークで送信し、送信先に送信するときに同じアルゴリズム+秘密鍵を使って暗号文を平文に変換する必要があります。

この暗号化と復号化のプロセスでは、同じアルゴリズム+秘密鍵が使用されます。

ここでは、元の平文を得るために、同じアルゴリズム+秘密鍵を使って平文を2回連続して暗号化していることがわかります。

これはコンピュータにおけるdifferent-or演算(英語ではもっぱらOR、略称はxor)とよく似ています。 different-or演算には2つの特徴があります:

  • 2進数の2桁が0なら同じ、1なら異なる。

  • different-orの後に2回数値を入力すると、元の数値そのものになります。

以下は、文字aを使用する例であり、2つの異なるまたは操作のための数字3は、最終的な結果がまだaであることがわかります。

これはビット演算なので、演算に使用する前に演算の引数を2進数に変換する必要があります。懹䲈 // 暗号化結果 I love you // 復号結果 上記のアルゴリズムでは、コンテンツはまず文字の配列に変換され、次に配列の各文字と、新しい文字を取得する演算を行うためのキーのシェーピング、そして最後に、文字の新しい配列を新しい文字列に変換します。

なぜ、内容文字列を直接キーで区別できないのでしょうか?文字列は数値を直接操作できませんが、文字は数値を操作できるので、文字列は文字配列に変換されます。

後述する暗号化・復号化メソッドの最下層ではバイナリを使用するため、暗号化・復号化のパラメータは最終的にバイナリのバイト配列に変換されて処理されます。

上記の方法では、暗号化と復号化は同じ鍵キーを使用します。通常、この方法は対称暗号化と呼ばれます。暗号化と復号化が異なる秘密鍵を使用する場合は、非対称暗号化と呼ばれます。

対称暗号化

対称暗号化では、両者が同じ秘密鍵とアルゴリズムで通信し、その後データを暗号化・復号化します。

以下は一般的な対称暗号化アルゴリズムです:DES、AES。

DES

DESのアルゴリズムは、コンピュータのデータと暗号化の種類の使用の情報処理を保護するために、米国政府機関であり、暗号アルゴリズムの従来の暗号システムは、広く使用されています。64ビットの暗号文を生成するために64ビットの鍵の制御の下で、アルゴリズムの入力は、平文の64ビットです。64ビットの鍵は、パリティビットの8ビットが含まれているので、56ビットの実際の有効なキーの長さ。56ビットの鍵と追加の8ビットのパリティを使用すると、最大64ビットのパケットサイズが生成されます。これは Feistel と呼ばれる技術を使った反復パケット暗号で、暗号化されたテキストブロックが半分に分割されます。DESは16のループを使用し、微分、置換、並べ替え、シフト操作の4つの基本操作を使用します。

以下はJDKを使った暗号化のサンプルコードです:

Xii999DE7LPx5io0awfOFw== // 暗号化結果
I love you // 復号結果 

上記のコードを実行した結果:

package com.wuxiaolong.EncrypteDecrypt;
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.security.Key;
import java.util.Base64;
/**
 * Description:
 *
 * 
 * @date 
 */
public class DESUtil {
 /**
 * オフセット変数、8バイトに固定
 */
 private final static String IV_PARAMETER = "";
 /**
 * 暗号化アルゴリズム
 */
 private static final String ALGORITHM = "DES";
 /**
 * 暗号化/復号化アルゴリズム - 動作モード - パディング・モード
 */
 private static final String CIPHER_ALGORITHM = "DES/CBC/PKCS5Padding";
 /**
 * デフォルトのエンコード
 */
 private static final String CHARSET = "utf-8";
 /**
 *  
 */
 private static final String KEY = "key";
 public static void main(String[] args) {
 String content = "愛してる。";
 String encptStr = encrypt(KEY,content);
 System.out.println(encptStr);
 String decptStr = decrypt(KEY,encptStr);
 System.out.println(decptStr);
 }
 /**
 * 鍵を生成する
 *
 * @param password
 * @return
 * @throws Exception
 */
 private static Key generateKey(String password) throws Exception {
 DESKeySpec dks = new DESKeySpec(password.getBytes(CHARSET));
 SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
 return keyFactory.generateSecret(dks);
 }
 /**
 * DES暗号化された文字列
 *
 * @param password パスワードを暗号化する。長さは8ビット以下にはできない。
 * @param data 暗号化される文字列
 * @return 暗号化されたコンテンツ
 */
 public static String encrypt(String password, String data) {
 if (password== null || password.length() < 8) {
 throw new RuntimeException("暗号化に失敗しました。キーは8ビット未満にはできません」);
 }
 if (data == null)
 return null;
 try {
 Key secretKey = generateKey(password);
 Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
 IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes(CHARSET));
 cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
 //  
 byte[] bytes = cipher.doFinal(data.getBytes(CHARSET));
 // base64エンコード JDK1.8以上のコードでは、Base64を直接使用することができる。,JDK1.7BASE64Encoderは以下の用途に使用できる。
 byte[] encode = Base64.getEncoder().encode(bytes);
 return new String(encode);
 } catch (Exception e) {
 e.printStackTrace();
 return data;
 }
 }
 /**
 * DES復号化された文字列
 *
 * @param password パスワードを復号化する。長さは8ビット以下にはできない。
 * @param data 復号化される文字列
 * @return 復号化された内容
 */
 public static String decrypt(String password, String data) {
 if (password== null || password.length() < 8) {
 throw new RuntimeException("暗号化に失敗しました。キーは8ビット未満にはできません」);
 }
 if (data == null)
 return null;
 try {
 Key secretKey = generateKey(password);
 Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
 IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes(CHARSET));
 cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
 // base64 
 byte[] decode = Base64.getDecoder().decode(data.getBytes(CHARSET));
 //  
 byte[] decrypt = cipher.doFinal(decode);
 return new String(decrypt, CHARSET);
 } catch (Exception e) {
 e.printStackTrace();
 return data;
 }
 }
} 

1997年にRSAデータ・セキュリティ社はDESチャレンジを開始し、有志が4ヶ月、41日、56時間、22時間を費やして56ビットのDES暗号化暗号文を4回に分けて解読しました。つまり、コンピュータの高速化が進んだ現在では、DES暗号化アルゴリズムは安全でないと考えられています。したがって、特に機密性の高いデータには非対称暗号化アルゴリズムを使用することが推奨されます。

AES

AES(Advanced Encryption Standard)はブロック暗号化規格です。この規格は DES の代替として使用され、様々な関係者によって分析され、世界中で広く使用されています。

DESは56ビットの鍵を使用するため、比較的容易に破ることができますが、AESは128、192、256ビットの鍵を使用でき、128ビットのグループでデータを暗号化・復号化するため、比較的安全です。完全な暗号化アルゴリズムは、理論上、網羅的な方法を用いない限り破られません。潔鍵長128ビットの暗号化データを破るために網羅的方法を使用することは非現実的であり、理論的な可能性があるだけです。統計によると、世界最速のコンピュータを使っても、128ビットの鍵長を網羅的に解読するには数十億年かかり、AESアルゴリズムの256ビットの鍵長を使って潔を破るのは言うまでもありません。

以下はAESショーのソースコードです:

Xii999DE7LPx5io0awfOFw== // 暗号化結果
I love you // 実行結果 

上記のコードを実行した結果:

DESに比べ、AESアルゴリズムは高速でリソース効率も高く、セキュリティレベルも高く、次世代の暗号化標準として知られています。世界にはAESの厚い壁を破る方法を研究している組織がまだありますが、潔を破るには長い時間がかかるため、AESは安全ですが、使用される時間は縮小し続けています。コンピュータの計算速度が向上し、新しいアルゴリズムの出現により、AESの攻撃はより激しくなるだけで、停止することはありません。

AESは現在、金融、オンライン取引、無線通信、デジタルストレージなどで広く使用されています。最も厳しいテストに耐えたが、いつかDESの足跡をたどるかもしれません。

対称暗号の特徴

利点

  • 高速。非対称暗号に比べて、対称暗号は性能がよく、暗号化と復号が速い。
  • 安全。比較的安全です。
  • コンパクト。暗号化後のコンテンツの長さは基本的にほとんど変わりません。

デメリット。

  • 2者が平文で共有鍵を送信して通信する場合、途中で乗っ取りや盗聴の問題が発生しやすい。
  • 通信する参加者の数が増えると、鍵の数が飛躍的に拡大します)/2)。
  • 鍵の数が膨大になるため、鍵の管理・保管が大きな問題になります。
  • 電子署名や否認防止に対応していません。

IV.非対称暗号方式

非対称暗号アルゴリズムでは、両者が通信を行う際に、あらかじめ秘密鍵のペアを生成しておき、公開鍵を交換します。通常、非対称暗号化には RAS アルゴリズムが使われます。

非対称鍵技術では、ユーザーであれルーターなどのネットワーク機器であれ、すべての参加者が、公開鍵と秘密鍵を含む非対称鍵アルゴリズムを使って事前に一対の鍵を生成する必要があります。公開鍵はサーバーに置き、この鍵システムに属するすべてのユーザーや機器に共有することができます。一方、秘密鍵は保有者だけが一意に所有できるように、保有者が厳密に保護する必要があります。

非対称暗号化には、安全であること、公開鍵をネットワーク経由で送信できることなど、多くの利点があります。しかし、暗号化速度が遅く、KB上のデータの暗号化には使用できません。

RSRの数学的原理、公開鍵暗号化秘密鍵復号化、秘密鍵署名公開鍵署名検証、公開鍵と秘密鍵の生成、大きなファイルを暗号化する方法、秘密鍵の管理方法など、RASアルゴリズムについて語れることはたくさんあります。これらについては、このセキュリティ・シリーズの他の記事で詳しく説明します。今回は、主な内容をコードに示しますが、ここではあまり多くを語りません。

RSA

ここで重要なのは、暗号化には相手の公開鍵が使われ、復号化には対応する秘密鍵が使われるということです。

コードを実行した結果

非対称暗号の特徴

動作の特徴:

  • ある鍵で暗号化されたデータは、別の鍵でしか復号化できません。
  • 一つの鍵は署名に使われ、一つの鍵は署名検証に使われます。

長所

  • 非対称鍵の配布は、交換された公開鍵の乗っ取りを心配する必要がないため、 より安全。
  • 鍵の数は参加者の数と同じ。
  • 公開鍵の交換において、事前に何らかの信頼関係を築く必要がないこと。
  • 電子署名と否認防止に対応。

デメリット

  • 暗号化に時間がかかる上位KBのデータの暗号化には使わず、データ量の少ない鍵の暗号化に使用。
  • 暗号化後、暗号文が長くなります。

完成しました!

知識を広め、価値を共有し、パートナーの注目とサポートに感謝し、私は諸葛小猿、インターネット労働者の闘争の不確実性です!

Read next

JSはいくつかの方法でオブジェクトを生成する

新しいオブジェクト;\nファクトリーパターン\nコンストラクタ・パターン\nプロトタイプ・パターン\nコンストラクタ・パターンとプロトタイプ・パターンの組み合わせ\n動的プロトタイプ・パターン\nnew Object() は {} と同じです。\nプロトタイプを作成します。

Aug 13, 2020 · 3 min read