EeBlog(テクニカルブログ)

第11回 排他的論理和(XOR)を利用した暗号化

前の2回は、「ビットフラグ」についてお話しました。
今回はビット演算つながりということで、 排他的論理和(XOR)を利用した暗号化について書いてみたいと思います。

現在ではここで紹介する程度の単純な暗号化はそのままで利用されることはないと思いますが、 様々な暗号化技術の基礎といえるものですので理解しておくとプログラミングの幅が広がると思います。

ビット演算ではおなじみの排他的論理和は2回行うと元に戻るという性質があります。

C = A ^ B;
D = C ^ B;

の場合、
1行目でBを使用してAをXOR変換します。Cができます。
2行目で出来上がったCに対して同じくBでXOR変換してやるとDができます。
変換前のAと2回変換したDが同じ値になる(A == D)という性質です。

これを暗号化に置き換えると、
暗号化したい文字列(A)にキーとなる値(B)を使用してXOR変換することで暗号化(C)します。
暗号化した文字列(C)は再びキー(B)を使用してXOR変換することで復元(D)することがでます。

public class XorTest {
     
     //==================================================
     // メイン
    //==================================================
     public static void main(String[] args) {
         String value = "肉と野菜と魚";
         String key = "果物";
         
         // 暗号化前出力
        print("暗号化前", value);

         // 暗号化
        byte[] byteEncodeArray = encode(value.getBytes(), key);
         value = new String(byteEncodeArray);
         
         // 暗号化後出力
        print("暗号化後", value);

         // 復元
        byte[] byteDecodeArray = decode(value.getBytes(), key);
         value = new String(byteDecodeArray);
         
         // 復元後出力
        print("復元後", value);

     }
     
     //==================================================
     // 暗号化
    //==================================================
     private static byte[] encode(byte[] src, String key) {
         byte[] byteKeyArray = new byte[0];
         byte[] byteEncArray = new byte[src.length];
         
         // キーの文字列を変換する文字列をカバーするまで繰り返す
        while(byteKeyArray.length < src.length) {
             byteKeyArray = (new String(byteKeyArray) + key).getBytes();
         }
         
         // 変換
        for (int i = 0; i < src.length; i++) {
             byteEncArray[i] = (byte)(src[i]^byteKeyArray[i]);
         }

         return byteEncArray;
     }
     
     //==================================================
     // 復元
    //==================================================
     private static byte[] decode(byte[] src, String key) {
         return encode(src, key);
     }
     
     //==================================================
     // ダンプ文字列取得
    //==================================================
     private static String getDump16(byte[] value) {
         
         StringBuffer buf = new StringBuffer();
         
         for (int i = 0; i < value.length; i++) {
             String hex = Integer.toHexString((int)value[i] & 255);
             
             // 4桁に揃える
            hex = "0000" + hex;
             hex = hex.substring(hex.length() - 4, hex.length());
             
             // バッファに追加(空白区切り、10桁ずつ改行)
             buf.append(hex + (i % 10 == 9?System.getProperty("line.separator"):" "));
         }
         return buf.toString().trim();
     }
     
     private static void print(String title, String value) {
         System.out.println("【 " + title + " 】");
         System.out.println("-----------------------------");
         System.out.println(value);
         System.out.println(getDump16(value.getBytes()));
         System.out.println();
         System.out.println();
     }

 }

人生の復元キーはどこにある…??