- 投稿日:2019-11-27T23:38:17+09:00
C# - ちょー雑な方法でFormのアイコンを生成する (Windows)
画面キャプチャ
サンプルコード
using System; using System.Drawing; using System.Windows.Forms; //using System.Runtime.InteropServices; class IconMakeTest:Form { // class NativeMethods // { // [DllImport("user32.dll", CharSet = CharSet.Auto)] // public extern static bool DestroyIcon(IntPtr handle); // } IconMakeTest() { GetHiconExample(); } static string[] iconDot = new string[]{ "................", ".###...##...##..", "..#...#..#.#..#.", "..#...#....#..#.", "..#...#....#..#.", "..#...#....#..#.", "..#...#....#..#.", "..#...#....#..#.", "..#...#....#..#.", "..#...#....#..#.", "..#...#....#..#.", "..#...#....#..#.", "..#...#....#..#.", "..#...#..#.#..#.", ".###...##...##..", "................", }; void GetHiconExample() { using ( Bitmap bmp = new Bitmap(16,16) ) { using ( Graphics g = Graphics.FromImage(bmp) ) { g.Clear(Color.White); } for(int y=0;y<16;y++){ for(int x=0;x<16;x++){ if (iconDot[y][x]=='#') { bmp.SetPixel(x,y,Color.Black); } } } IntPtr Hicon = bmp.GetHicon(); Icon newIcon = Icon.FromHandle(Hicon); this.Icon = newIcon; //NativeMethods.DestroyIcon(newIcon.Handle); } } [STAThread] static void Main(string[] args) { Application.Run(new IconMakeTest()); } }参考サイト
- 投稿日:2019-11-27T19:54:27+09:00
「MonKey - Productivity Commands」のコマンド操作でUnity開発を効率化する
PONOS Advent Calendar 2019の2日目の記事です。
昨日は@honeniqさんのfish shellのはじめかた 2019冬でした。
はじめに
Asset Storeで販売されているアセット「MonKey - Productivity Commands」を導入することにより、コマンドでUnityの各種操作を実行できるようになります。
Unityエディタ上での開発速度の向上が期待できると感じたので、紹介したいと思います。なお、
- Unity 2019.2.1.12f1
- MacOS 10.14.6
の環境で動作確認しています。
「MonKey - Productivity Commands」とは
MonKey - Productivity Commands - Asset Store
- 1シート$40
- 対応するUnityバージョンは2017.4.1以上
- コマンド操作で様々な機能を実行して開発できる。
- デザイナー、アーティスト、プログラマのための130個以上のコマンドを用意。
- 属性を使うことでカスタムコマンドの追加も可能。
- 公式ドキュメント(MonKey - User Guide)
導入
- Unity Asset Storeで購入後、プロジェクトにインポートしてください。
(デモが不要であれば、Plugins/Monkey Commander/Demo!は削除して構いません)- インポートが完了するとGetting Startedのダイアログが起動しますが、使い始めるために追加設定は必要ないので、
そのまま閉じてしまいましょう。
- 以上で導入は完了です。非常に簡単ですね。
- 「`」キーを入力すると、Monkeyのコマンドパレットが表示され、コマンドの入力が可能になります。
基本的な使い方
コマンドパレットに検索文字列を入力するとコマンドの候補が表示されます。
「↑」「↓」キーで候補の中から実行するコマンドを選択、「Enter」キーでコマンドを実行します。
- コマンドによっては実行時に追加のパラメータ入力が必要になるものもあります。
- 操作感はMacアプリケーションの「Alfred」やUnityアセットの「Quick Search」に近いので、これらのアプリケーションを利用している方は馴染みやすいと思います。
使用例:Imageコンポーネントを持つGameObjectの名前の末尾に「_IMG」を追加する
ここからはMonKeyを活用する一例を紹介します。
以下のようなシーンをサンプルに、Imageコンポーネントを持つすべてのGameObjectについて、それが「イメージを表示しているオブジェクト」であると認識しやすいように、名前の末尾に「_IMG」を追加してみましょう。
※Man、Woman、Cat、DogのGameObjectがそれぞれImageコンポーネントを持っています。この処理を通常の手順で実現しようとする場合、名前の変更を1GameObjectずつ手作業で行わなくてはならず、非常に手間がかかります。しかし、MonKeyを使用することで、その手順を大幅に短縮することが可能となります。
今回の使用例で使用するコマンドは以下の2つです。Select Scene Objects of Type
指定した型を持つGameObjectをすべて選択します。
省略コマンドとして「ST」が用意されています。Rename Add Name Suffixes
選択されているすべてのGameObjectの名前の末尾に指定した文字列を連結します。
省略コマンドとして「RNS」が用意されています。では、MonKeyを使用した場合の手順を見てみましょう。
- 「`」でMonKeyのコマンドパレットを開く。
- 「ST」を入力し、「Select Scene Objects of Type」コマンドを選択する。
- 「Select Scene Objects of Type」コマンドの追加パラメータ入力として、型名の入力フィールドが表示されるので、「image」を入力してコマンドを実行する。
- ここまでで、Imageコンポーネントを持つGameObjectだけをすべて選択できた状態となる。
- 「`」で再度MonKeyのコマンドパレットを開く。
- 「RNS」を入力し、「Rename Add Name Suffixes」コマンドを選択する。
- 「Rename Add Name Suffixes」コマンドの追加パラメータ入力として、連結する文字列の入力フィールドが表示されるので、「_IMG」を入力してコマンドを実行する。
- 選択中のすべてのGameObjectの名前が「〜_IMG」の形に変更される。
以上です。
1個1個のGameObjectを選択して名前を編集する必要がないため、非常に効率的です。おわりに
本来、複数の操作を組み合わせなければ実現できない処理でも、MonKeyを活用することで1コマンドで実行することができるようになります。
日頃頻繁に実行している処理ほど操作時間や手順が短縮されることによる恩恵は大きいので、「昨日も同じ手順で面倒な処理をしていた」
と心当たりがある方は導入を検討してみてはいかがでしょうか。
明日は@blockさんです!
- 投稿日:2019-11-27T17:06:29+09:00
和暦の環境で西暦の日付の文字列をパースする
問題
Windowsのカレンダーを和暦にした状態で
yyyy/MM/dd HH:mm:ss
形式の西暦の文字列をDateTime.Parse()
でパースすると、yyyy
の部分が元号の年として認識されてしまいます。var date = "2019/11/21 01:23:45"; Console.WriteLine(DateTime.Parse(date)); //令和2019/11/21 1:23:45解決方法
DateTime.Parse()
に特定のカルチャに依存しないカルチャ情報(CultureInfo.InvariantCulture
)を指定してあげると、yyyy
の部分を西暦として認識してくれます。var date = "2019/11/21 01:23:45"; Console.WriteLine( DateTime.Parse(date, CultureInfo.InvariantCulture) ); //令和1/11/21 1:23:45
- 投稿日:2019-11-27T17:06:29+09:00
和暦の環境で西暦の日付の文字列をパースする/DateTime変数を西暦の文字列に変換する
問題
Windowsのカレンダーを和暦にした状態で
yyyy/MM/dd HH:mm:ss
形式の西暦の文字列をDateTime.Parse()
でパースすると、yyyy
の部分が元号の年として認識されてしまいます。
また、DateTime
型の変数を単純にToString()
すると、和暦の文字列が得られてしまいます。var date = "2019/11/21 01:23:45"; Console.WriteLine(DateTime.Parse(date)); //令和2019/11/21 1:23:45 var date2 = DateTime.Parse("令和1/11/21 01:23:45"); Console.WriteLine(date2.ToString("yyyy/MM/dd HH:mm:ss")); //01/11/21 01:23:45解決方法
DateTime.Parse()
およびToString()
に特定のカルチャに依存しないカルチャ情報(CultureInfo.InvariantCulture
)を指定してあげると、yyyy
の部分を西暦として認識してくれます。var date = "2019/11/21 01:23:45"; Console.WriteLine( DateTime.Parse(date, CultureInfo.InvariantCulture) ); //令和1/11/21 1:23:45 var date2 = DateTime.Parse("令和1/11/21 01:23:45"); Console.WriteLine( date2.ToString("yyyy/MM/dd HH:mm:ss", CultureInfo.InvariantCulture) ); //2019/11/21 01:23:45
- 投稿日:2019-11-27T15:48:15+09:00
【Unity(C#),Python】API通信勉強メモ②Flaskでローカルサーバー立ち上げ
今回やること
この記事は前回の勉強の続きです。
【前回】:【Unity(C#)】API通信勉強メモ①前回できなかったPostの処理を学びます。
なんもわからんなりの解釈が山盛りなのでマサカリ、オールオッケーです。
Flask
Flask(フラスク)は、プログラミング言語Python用の、軽量なウェブアプリケーションフレームワークである。標準で提供する機能を最小限に保っているため、自身を「マイクロフレームワーク」と呼んでいる。
Wikipediaより引用
今回はFlaskというPythonのウェブアプリケーションフレームワーク1を使用して
ローカルにアプリケーションサーバーを立て、Unity側からHTTPリクエスト(POST)を送る
までやってみようと思います。おおよそ、参考リンクに沿って進めていきます。
【参考リンク】:Pythonと連携する方法
Flaskのインストール
$pip install flaskGETリクエスト
まずはFlaskで立てたローカルのサーバーにGETリクエストを送ってみます。
Python側の処理from flask import Flask app = Flask(__name__) @app.route("/", methods=['GET']) def index(): return "HIKAKIN「ブンブン!ハローユーチューブ!」" if __name__ == "__main__": app.debug = True app.run()Unity側の処理は下記リンクから拝借しました。
【参考リンク】:UnityでHTTPに接続するUnity側でHTTPリクエストを送るスクリプトusing System.Collections; using UnityEngine.Networking; using UnityEngine; public class HTTPGet : MonoBehaviour { //接続するURL private const string URL = "http://localhost:5000/"; void Start() { //コルーチンを呼び出す StartCoroutine("OnSend", URL); } IEnumerator OnSend(string url) { //指定したURLでGET UnityWebRequest webRequest = UnityWebRequest.Get(url); //URLに接続して結果が戻ってくるまで待機 yield return webRequest.SendWebRequest(); //エラーが出ていないかチェック if (webRequest.isNetworkError) { //通信失敗 Debug.Log(webRequest.error); } else { //通信成功 Debug.Log("Get" + " : "+webRequest.downloadHandler.text); } } }成功しました。
①Python側(VSC)でデバッグを開始
②UnityでPlay
という順番です。POSTリクエスト
次はFlaskで立てたローカルのサーバーにPOSTリクエストを送ってみます。
@app.route("/", methods=['POST', 'GET'])
にPOSTを追加しただけです。from flask import Flask app = Flask(__name__) @app.route("/", methods=['POST', 'GET']) def index(): return "HIKAKIN「ブンブン!ハローユーチューブ!」" if __name__ == "__main__": app.debug = True app.run()実際にやってみて思ったこととしては結局POSTとGETは何が違うんだよってことです。
この疑問に関しては下記リンクを見て一旦深く考えるのを止めることにしました。
【引用元】:GETとPOSTの違いについて本当はGETでやるべきこともPOSTでできてしまうのです。
やろうと思えばすべての処理をPOSTで作れてしまうのです。
この辺りは思想的な話もあるので、何とも言えない部分です。次回やること
Postの処理も上手くいったので次回はUnity側から入力した情報を登録 & ログインする機能を作っていきます。
とりあえずわかっていることとしては、
リクエストを送る際に情報を渡す方法として、
Unity側にWWW.Form
が用意されていることです。//POSTする情報 WWWForm form = new WWWForm(); form.AddField("user_id", idInputField.text, Encoding.UTF8); form.AddField("password",passInputField.text, Encoding.UTF8);上記のようにUnity側でログイン画面に入力したIDやパスワードをサーバーに送れる。。。はずです。
- 投稿日:2019-11-27T15:46:15+09:00
C# usingステートメント
ファイル操作でよく使う
参考記事:https://www.sejuku.net/blog/43105
- 投稿日:2019-11-27T07:43:56+09:00
[C#] Publishされた単一EXEが展開する先の一時フォルダのパス取得
地味に困ったので投稿。
Assembly.GetExecutingAssembly().Location以上のコードを、展開された先で実行されるdll上で実行すれば取得できる。
Environment.GetCommandLineArgs()[0]因みに、展開元のパスは基本的に上のコードで取得している。
<PublishSingleFile>true</PublishSingleFile>現状、上のタグを追加してPublishされた単一EXEファイルを実行する際の展開先には、dllのみが展開されるだけで、pbdファイルが含まれていない。
それだとエラー時の詳細情報が取得できないので、それらを取得するためのpbdファイルを移動するために展開先のパスが必要だった。
何故、pdbファイルが展開されないのかは不明。。。知っている方がいれば、教えていただけると幸いです。
- 投稿日:2019-11-27T05:35:59+09:00
C#でAES暗号化アルゴリズムを外部ライブラリに一切頼らず完全実装してみた
はじめに
今回、暗号化技術「AES」(Advanced Encryption Standard)について、深く知り学びたいとふと思ってしまったので、C#でアルゴリズムを完全再現してみました。
今回は学習目的ですが、本来であれば標準ライブラリに頼るべきです。また、実装にあたって高度な数学は避けられません。
私の範囲を超えたものは、基本的に外部記事に解説を委ねます。今回、以下の記事を参考にさせて頂きました。
Wikipedia様:
出典: フリー百科事典『ウィキペディア(Wikipedia)』
・Advanced Encryption Standard
・Rijndael S-box
・Rijndael MixColumns
・AES key scheduleWikiwand様:
・Block cipher mode of operationAppliedGo様:
・(YouTube)AES Rijndael Cipher explained as a Flash animation・The Advanced Encryption Standard (Rijndael)
AESとは何か
※あくまで主観です
今の時代、Googleで探せばいくらでも情報が手に入りますが、
これに関しては、既知の情報をコピー&ペーストしたような情報記事ばかりで、正確でわかりやすい情報を見つけるのに苦労しました。AESとは、アメリカ国立標準技術研究所で標準暗号とされている共通鍵暗号アルゴリズムです。
Rijndaelが採用されています。(ラインデールと読むそうです。かっこいい。)暗号化プロセス
鍵長128bitの場合、ラウンド数は合計10です。
暗号化プロセスは、以下の通りです。
環境
・Visual Studio 2019 Professional
・Windows 10 1903 Build 18362.476
・C#
・.NET Framework 4.7.2開発期間: 1.5日
実装
SubBytes
S-BOXと呼ばれるテーブルを使用して、バイトを変換します。
S-BOXのテーブルは以下の通りです。
なぜこうなっているのかは私の範囲外ですのでwikipedia様にお任せします。
ソースコード
実際にコードでSBOXの値を求めるにあたって、case-switch文で関数定義しました。
完全に脳死してます。
より良い方法はありますが、とりあえず動作していますし速度は求めていないので今回はこれで行きます。コメント欄よりご指摘を頂き、ソースコードを修正しました。
SBOX.csprivate static readonly byte[] sbox_table = { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }; public static byte Convert(byte _byte_) { return sbox_table[_byte_]; }ShiftRows
4バイト単位の行を一定規則で左シフトします。
例として、以下の画像の通りです。
・2段目を1個左シフト
・3段目を2個左シフト
・4段目を3個左シフト
ソースコード
1行目は操作の必要がありませんが、わかり易さのために残しています。
Cryption.csprivate static byte[] ShiftRows(byte[] bytes) { byte[] result = new byte[bytes.Length]; result[ 0] = bytes[ 0]; result[ 1] = bytes[ 1]; result[ 2] = bytes[ 2]; result[ 3] = bytes[ 3]; result[ 4] = bytes[ 5]; result[ 5] = bytes[ 6]; result[ 6] = bytes[ 7]; result[ 7] = bytes[ 4]; result[ 8] = bytes[10]; result[ 9] = bytes[11]; result[10] = bytes[ 8]; result[11] = bytes[ 9]; result[12] = bytes[15]; result[13] = bytes[12]; result[14] = bytes[13]; result[15] = bytes[14]; return result; }MixColumns
Rijindaelのガロア体という、定数を利用して計算を行います。
具体的には、ガロア体の4つの数字の座標ベクトルにMDS(最大距離分離)行列を乗算します。
これも、高度な数学で私の範囲を超えていますので、外部記事にお任せします。
・巡回行列 - Wikipedia
・MDS Matrix
・MDS行列 の意味・用法を知るソースコード
ガロア体は以下のように定義しました。
byte[] matrix = { 0x02, 0x03, 0x01, 0x01, 0x01, 0x02, 0x03, 0x01, 0x01, 0x01, 0x02, 0x03, 0x03, 0x01, 0x01, 0x02 };当ソースコードではわかり易さの為、ガロア体を定数として定義して使用していませんが
どちらにせよコンスタントな値であるため、直接書いても良いです。Cryption.csprivate static byte[] MixColumns(byte[] bytes) { byte[] result = new byte[bytes.Length]; byte[,] bytes2d = new byte[4, 4]; bytes2d = Bytes16To2DBytes4(bytes); byte[] matrix = { 0x02, 0x03, 0x01, 0x01, 0x01, 0x02, 0x03, 0x01, 0x01, 0x01, 0x02, 0x03, 0x03, 0x01, 0x01, 0x02 }; byte[,] matrix2d = new byte[4, 4]; matrix2d = Bytes16To2DBytes4(matrix); byte[,] resultBytes2d = new byte[4, 4]; for (int c = 0; c <= 3; c++) { resultBytes2d[0, c] = (byte)((GMul(0x02, bytes2d[0, c])) ^ (GMul(0x03, bytes2d[1, c])) ^ (GMul(0x01, bytes2d[2, c])) ^ (GMul(0x01, bytes2d[3, c]))); resultBytes2d[1, c] = (byte)((GMul(0x01, bytes2d[0, c])) ^ (GMul(0x02, bytes2d[1, c])) ^ (GMul(0x03, bytes2d[2, c])) ^ (GMul(0x01, bytes2d[3, c]))); resultBytes2d[2, c] = (byte)((GMul(0x01, bytes2d[0, c])) ^ (GMul(0x01, bytes2d[1, c])) ^ (GMul(0x02, bytes2d[2, c])) ^ (GMul(0x03, bytes2d[3, c]))); resultBytes2d[3, c] = (byte)((GMul(0x03, bytes2d[0, c])) ^ (GMul(0x01, bytes2d[1, c])) ^ (GMul(0x01, bytes2d[2, c])) ^ (GMul(0x02, bytes2d[3, c]))); } result = Bytes2D4ToBytes16(resultBytes2d); return result; }MDS(最大距離分離)行列を乗算
式が変換先の型の範囲外の値を生成した場合に、オーバーフローを検出させないために、unchecked()
が必要です。public static byte GMul(byte a, byte b) { byte p = 0; for (int counter = 0; counter < 8; counter++) if ((b & 1) != 0) p ^= a; bool bs = (a & 0x80) != 0; a <<= 1; if (bs) a ^= unchecked((byte)0x11B); b >>= 1; return p; }KeySchedule : RotWord
ラウンド毎に行われる、新しい鍵の生成です。
まずはじめに、鍵の行(縦)4行目をとり、RotWordという入れ替え処理を行います。
次にRijindael S-BOX定数を用いて、該当行を変換します。SBOX.Convert([byte]);また、
RCON
(RoundConstant)と呼ばれる、ラウンドコンスタント定数を使用しています。private static readonly byte[] RCON = { 0x00000000, 0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010, 0x00000020, 0x00000040, 0x00000080, 0x0000001B, 0x00000036 };ソースコード
Cryption.csprivate static void KeySchedule(byte[] bytes, int currentRound) { byte[,] bytes2d = Bytes16To2DBytes4(bytes); byte[,] round_key = new byte[4, 4]; byte[] r = new byte[16]; byte[] r_ = new byte[16]; //Rot Word //一旦値を格納 r[ 3] = CURRENT_CHIPHER_KEY[ 3]; //09 r[ 7] = CURRENT_CHIPHER_KEY[ 7]; //cf r[11] = CURRENT_CHIPHER_KEY[11]; //4f r[15] = CURRENT_CHIPHER_KEY[15]; //3c //↓ 一番下を一番上に持ってくる r_[ 3] = CURRENT_CHIPHER_KEY[ 7]; //cf r_[ 7] = CURRENT_CHIPHER_KEY[11]; //4f r_[11] = CURRENT_CHIPHER_KEY[15]; //3c r_[15] = CURRENT_CHIPHER_KEY[ 3]; //09 //↓ s-box変換 r_[ 3] = SBOX.Convert(r_[ 3]); //8a r_[ 7] = SBOX.Convert(r_[ 7]); //84 r_[11] = SBOX.Convert(r_[11]); //eb r_[15] = SBOX.Convert(r_[15]); //01 r[ 0] = CURRENT_CHIPHER_KEY[ 0]; r[ 4] = CURRENT_CHIPHER_KEY[ 4]; r[ 8] = CURRENT_CHIPHER_KEY[ 8]; r[12] = CURRENT_CHIPHER_KEY[12]; round_key[0, 0] = (byte)(CURRENT_CHIPHER_KEY[ 0] ^ r_[ 3] ^ RCON[currentRound]); round_key[1, 0] = (byte)(CURRENT_CHIPHER_KEY[ 4] ^ r_[ 7] ^ RCON[0]); round_key[2, 0] = (byte)(CURRENT_CHIPHER_KEY[ 8] ^ r_[11] ^ RCON[0]); round_key[3, 0] = (byte)(CURRENT_CHIPHER_KEY[12] ^ r_[15] ^ RCON[0]); for (int x = 0; x <= 3; x++) //0,1,2 (3) { //0は除きたい(横インデックス1から埋め込んでいく)ので x は 1 2 3 のみに絞る if (x == 0) continue; round_key[0, x] = (byte)(CURRENT_CHIPHER_KEY[ 0 + (1 * x)] ^ round_key[0, x - 1]); round_key[1, x] = (byte)(CURRENT_CHIPHER_KEY[ 4 + (1 * x)] ^ round_key[1, x - 1]); round_key[2, x] = (byte)(CURRENT_CHIPHER_KEY[ 8 + (1 * x)] ^ round_key[2, x - 1]); round_key[3, x] = (byte)(CURRENT_CHIPHER_KEY[12 + (1 * x)] ^ round_key[3, x - 1]); } CURRENT_CHIPHER_KEY = Bytes2D4ToBytes16(round_key); }初期ラウンドにやること
初期ラウンドの
AddRoundKey
では、暗号化するByteと鍵とのXorをとります。byte[] result = new byte[bytes.Length]; for (int x = 0; x < bytes.Length; x++) { result[x] = (byte)(bytes[x] ^ CIPHER_KEY[x]); }暗号化するByte: 32 88 31 e0 43 5a 31 37 f6 30 98 07 a8 8d a2 34 鍵: 2b 28 ab 09 7e ae f7 cf 15 d2 15 4f 16 a6 88 3C 結果: 19 A0 9A E9 3D F4 C6 F8 E3 E2 8D 48 BE 2B 2A 08結果
ラウンド1
ラウンド2
ラウンド3
ラウンド4
ラウンド5
ラウンド6
ラウンド7
ラウンド8
ラウンド9
ラウンド10
無事、暗号化に成功しました。
最後に
今回は、AES暗号化アルゴリズムを外部ライブラリに頼らずフル実装してみました。
解説に関しては、私が高校数学を未だ習っていない為外部に頼りきりですが、プロジェクトを通して、本当に沢山のことを学べました。
また、当プロジェクトでは暗号化のみ行っていますが、また機会があれば復号化にもチャレンジしてみたいです。今回のプロジェクトは、Githubリポジトリよりフルソースコードを閲覧できます。
・GitHub当記事に間違いや訂正するべき点がございましたら、お手数ですがコメント欄よりご指摘を頂けますと幸いです。