Façadeパターン
「窓口」となるクラスを作ってシンプルに利用する
façadeとはフランス語を語源とする単語で「建物の正面」という意味です。発音するときはファサードの「サ」にアクセントを置きます。
プログラムを作っていくと、最初は小さなものでも、だんだん大きくなっていきます。 たくさんのクラスが出来て、相互に関係しあい、複雑になっていきます。 クラスを使う場合には、それらの関係を正しく理解して、 正しい順番にメソッドを呼び出す必要があります。 大きなプログラムを使って処理を行う場合、 関係しあっているたくさんのクラスを適切に制御しなくてはいけません。 その処理を行うための「窓口」を用意しておくと、 個別にたくさんのクラスを制御しなくても、「窓口」に対して、要求するだけですみます。
例えば、市役所などに申請書類を提出しなければならないとき、いろいろな課をまわって許可をもらうなどしていては、時間もかかりますし、初めてではまずどこに行ったらいいかも分からないかもしれません。しかし、総合窓口のようなところに申請書類を提出するだけですめば簡単です。誰でも簡単に申請できるわけです。
Façadeパターンは、既存のクラスを複数組み合わせて使う手順を、「窓口」となるクラスを作ってシンプルに利用できるようにするパターンです。
つまり、 Façadeパターンとは、インタフェースを少なくすることです。クラスやメソッドがたくさん見えてしまうと、どれを使っていいか迷いますし、また、呼び出しの順番にも注意しなければなりません。注意しなければならないということは、間違いやすいということです。そして、インタフェースが少ないということは、部品としての再利用もしやすなるということです。
例えば、データベースに対し何でもできてしまうクラスがあったとします。今、データベースを検索するだけのプログラムを作ろうとしているときに、そのような何でもできてしまうクラスは必要ありません。削除や更新のメソッドはいらないわけです。これらのメソッドがあると、誤って使ってしまうこともあるでしょうし、どのメソッドを使うかの選択肢が多くなって迷ってしまうこともあるかもしれません。このようなときには、その何でもできてしまうクラスを継承して、あるいはそのクラスに処理を委譲することによって、メソッドを検索関係だけに絞ることも必要なのです。
また、クラスを設計するときには、どのメソッドを public にするかをよく考える必要があります。あまりに多くのメソッドを public にしてしまうと、クラス内部を修正しにくくなります。
Façadeパターンは、パターンといえばパターンですが、ある程度の規模になれば、だれでも使うものです。
しかし、複雑なプログラムの内部を熟知しているプログラマーは、 Façade を作りたがらないかもしれません。それは、その熟練プログラマーの頭の中には、システムの内容がすべて入っていて、たくさんのクラスの相互関係が分かっているからかもしれません。あるいは、自分の技術を誇り、他のプログラマーに優越感をもてるからかもしれません。
あるプログラマーが「このクラスを呼ぶ前にはこっちを呼ばなくちゃいけない。こっちのメソッドの呼び出し前には、このクラスに登録しておく必要がある。」といった話を「得意げに」するときには、 Façadeパターンを導入する必要があることを示唆しています。
はっきりと言葉で表現できるノウハウは、プログラマーの頭の中に隠しておくべきものではなく、コードとして表現しておくべきものなのです。
例題
文字列の暗号化、復号化を行います。
実行結果
暗号化する文字列
|
Façadeパターンを使用しない例 Main.java public class Main {
public static void main(String[] args) {
// 対象文字列
String plainText = "暗号化する文字列";
// 暗号化キー
String encryptingKey = "ABCDEFGHIJKLMNOP";
// 暗号化する
SecretKeySpec secretKey = new SecretKeySpec(encryptingKey.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encryptedData = cipher.doFinal(plainText.getBytes());
String encryptedText = new String(Base64.getEncoder().encode(encryptedData));
//暗号化文字列の表示
System.out.println(encryptedText);
// :
// :
// 復号化する
cipher.init(Cipher.DECRYPT_MODE, secretKey);
encryptedData = Base64.getDecoder().decode(encryptedText);
byte[] decryptedData = cipher.doFinal(encryptedData);
String decryptedText = new String(decryptedData);
// 結果表示
System.out.println(decryptedText);
}
}
|
Façadeパターンを使用した例 AES.java public class AES {
public static String encrypt(String plainText, String encryptingKey) throws Exception {
SecretKeySpec secretKey = new SecretKeySpec(encryptingKey.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
// 暗号化する
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encryptedData = cipher.doFinal(plainText.getBytes());
return new String(Base64.getEncoder().encode(encryptedData));
}
public static String decrypt(String encryptedText, String encryptingKey) throws Exception {
byte[] encryptedData = Base64.getDecoder().decode(encryptedText);
SecretKeySpec secretKey = new SecretKeySpec(encryptingKey.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
//復号化する
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] decryptedData = cipher.doFinal(encryptedData);
return new String(decryptedData);
}
}
Main.java public class Main {
public static void main(String[] args) {
// 対象文字列
String plainText = "暗号化する文字列";
// 暗号化キー
String encryptingKey = "ABCDEFGHIJKLMNOP";
//暗号化する
String encryptedText = AES.encrypt(plainText, encryptingKey);
//暗号化文字列の表示
System.out.println(encryptedText);
// :
// :
//復号化する
String decryptedText = AES.decrypt(encryptedText, encryptingKey);
// 復号化文字列の表示
System.out.println(decryptedText);
}
}
|
|
この例では、比較的単純でクラスも2つ(SecretKeySpec、Cipher)しか利用していません。それでも、どのようにインスタンスを生成して、メソッドは何を呼んで、引数は何で...と、手順を踏まなければなりません。もしこれがいつも決まりきった手順なら、あらかじめ用意しておけばよいのです。 |
Façadeパターンでは、複雑な手順は、「窓口」となるクラスを作ってその中に入れたため、シンプルに利用できるようになりました。 |
|
Façadeパターンを使用しない例 main.cpp #include <Windows.h>
#include <WinCrypt.h>
#include <string>
#include <iostream>
using namespace std;
#define KEYLENGTH 0x0080 * 0x10000
int main()
{
// 対象文字列
string plainText = "暗号化する文字列";
// 暗号化キー
string encryptingKey = "ABCDEFGHIJKLMNOP";
HCRYPTPROV hProv;
HCRYPTHASH hHash;
HCRYPTKEY hKey;
// CSPのハンドル
CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, 0);
// ハッシュ計算のインスタンス
CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash);
// ハッシュ値の計算
byte workBytes[1000] = {0};
const char* p1 = encryptingKey.c_str();
strcpy((char*)workBytes, p1);
DWORD keyLen = strlen(p1);
CryptHashData(hHash, (BYTE*)p1, keyLen, 0);
// 暗号化
CryptDeriveKey(hProv, CALG_RC4, hHash, KEYLENGTH, &hKey);
const char* p2 = plainText.c_str();
strcpy((char*)workBytes, p2);
DWORD dwDataLen = strlen(p2);
CryptEncrypt(hKey, 0, false, 0, workBytes, &dwDataLen, sizeof(workBytes));
string encryptText((char*)workBytes);
DWORD dwDst = 0;
LPSTR pstrDst = "";
CryptBinaryToStringA(workBytes, encryptText.length(),
CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, NULL, &dwDst);
pstrDst = new CHAR[dwDst + 1];
CryptBinaryToStringA(workBytes, encryptText.length(),
, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, pstrDst, &dwDst);
string encryptedText(pstrDst);
delete[] pstrDst;
//暗号化文字列の表示
cout << encryptedText << endl;
// 復号化
CryptStringToBinaryA(encryptedText.c_str(), 0, CRYPT_STRING_BASE64, workBytes, &dwDataLen, NULL, NULL);
CryptDeriveKey(hProv, CALG_RC4, hHash, KEYLENGTH, &hKey);
CryptDecrypt(hKey, 0, false, 0, workBytes, &dwDataLen);
string decryptedText((char*)workBytes);
// 復号化文字列の表示
cout << decryptedText << endl;
// 後始末
CryptDestroyHash(hHash); // Hash
CryptDestroyKey(hKey); // 復号キー
CryptReleaseContext(hProv, 0); // CSP
return 0;
}
|
Façadeパターンを使用した例 CSP.h #include <Windows.h>
#include <string>
class CSP
{
private:
static const long KEYLENGTH = 0x0080 * 0x10000;
HCRYPTPROV hProv;
HCRYPTHASH hHash;
HCRYPTKEY hKey;
public:
CSP(void);
CSP(std::string);
virtual ~CSP(void);
std::string encrypt(std::string);
std::string decrypt(std::string);
}; CSP.cpp #include "CSP.h"
#include <WinCrypt.h>
#include <cstring>
#define BUUFER_SIZE 1000
using namespace std;
CSP::CSP(void) {}
CSP::CSP(string encryptingKey) {
// CSPのハンドル
CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, 0);
// ハッシュ計算のインスタンス
CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash);
// ハッシュ値の計算
byte keyBytes[BUUFER_SIZE];
const char* p = encryptingKey.c_str();
strcpy_s((char*)keyBytes, sizeof(keyBytes), p);
DWORD keyLen = strlen(p);
CryptHashData(hHash, (BYTE*)p, keyLen, 0);
}
CSP::~CSP(void) {
CryptDestroyHash(hHash); // Hash
CryptDestroyKey(hKey); // 復号キー
CryptReleaseContext(hProv, 0); // CSP
}
string CSP::encrypt(string plainText) { // 暗号化
CryptDeriveKey(hProv, CALG_RC4, hHash, KEYLENGTH, &hKey);
const char* p = plainText.c_str();
DWORD dwDataLen = strlen(p);
byte encryptBytes[BUUFER_SIZE];
strcpy_s((char*)encryptBytes, sizeof(encryptBytes), p);
CryptEncrypt(hKey, 0, false, 0, encryptBytes, &dwDataLen, sizeof(encryptBytes));
string encryptText((char*)encryptBytes);
CryptBinaryToStringA(encryptBytes, encryptText.length(),
CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, NULL, &dwDataLen);
LPSTR pstrDst = new CHAR[dwDataLen + 1];
CryptBinaryToStringA(encryptBytes, encryptText.length(),
CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, pstrDst, &dwDataLen);
string encryptedText(pstrDst);
delete[] pstrDst;
return encryptedText;
}
string CSP::decrypt(string encryptedText) { // 復号化
DWORD dwDataLen = encryptedText.length();
byte decryptBytes[BUUFER_SIZE] = { 0 };
CryptStringToBinaryA(encryptedText.c_str(), 0, CRYPT_STRING_BASE64, decryptBytes, &dwDataLen, NULL, NULL);
CryptDeriveKey(hProv, CALG_RC4, hHash, KEYLENGTH, &hKey);
CryptDecrypt(hKey, 0, false, 0, decryptBytes, &dwDataLen);
string decryptedText((char*)decryptBytes);
return decryptedText;
}
main.cpp #include <iostream>
#include <string>
using namespace std;
#include "CSP.h"
int main() {
// 対象文字列
string plainText = "暗号化する文字列";
// 暗号化キー
string encryptingKey = "ABCDEFGHIJ";
CSP csp(encryptingKey);
//暗号化する
string encryptedText = csp.encrypt(plainText);
//暗号化文字列の表示
cout << encryptedText << endl;
// :
// :
//復号化する
string decryptedText = csp.decrypt(encryptedText);
// 復号化文字列の表示
cout << decryptedText << endl;
return 0;
}
|
|
この例では比較的単純ですが、それでもどのようにインスタンスを生成して、メソッドは何を呼んで、引数は何で...と、手順を踏まなければなりません。もしこれがいつも決まりきった手順なら、あらかじめ用意しておけばよいのです。 |
Façadeパターンでは、複雑な手順は、 「窓口」となるクラスを作ってその中に入れたため、シンプルに利用できるようになりました。 |
|
Façadeパターンを使用しない例 Program.cs class Program
{
static void Main(string[] args)
{
string plainText = "暗号化する文字列";
TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider();
byte[] desKey = des.Key; // 暗号化キー
byte[] desIV = des.IV; // 初期化ベクタ
// 暗号化する
byte[] source = Encoding.Unicode.GetBytes(plainText);
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms,
des.CreateEncryptor(desKey, desIV),
CryptoStreamMode.Write);
cs.Write(source, 0, source.Length);
cs.Close();
byte[] destination = ms.ToArray();
ms.Close();
string encryptedText = Convert.ToBase64String(destination);
// 復号化する
source = Convert.FromBase64String(encryptedText);
ms = new MemoryStream();
cs = new CryptoStream(ms,
des.CreateDecryptor(desKey, desIV),
CryptoStreamMode.Write);
cs.Write(source, 0, source.Length);
cs.Close();
destination = ms.ToArray();
ms.Close();
string decryptedText = Encoding.Unicode.GetString(destination);
// 結果表示
Console.WriteLine(decryptedText);
}
}
|
Façadeパターンを使用した例 TripleDES.cs class TripleDES
{
private TripleDESCryptoServiceProvider des;
private byte[] desKey; // 暗号化キー
private byte[] desIV; // 初期化ベクタ
public TripleDES()
{
des = new TripleDESCryptoServiceProvider();
desKey = des.Key; // 暗号化キー
desIV = des.IV; // 初期化ベクタ
}
public string Encrypt(string plainText)
{
// 暗号化する
byte[] plainData = Encoding.Unicode.GetBytes(plainText);
TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider();
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms,
des.CreateEncryptor(desKey, desIV),
CryptoStreamMode.Write);
cs.Write(plainData, 0, plainData.Length);
cs.Close();
byte[] encryptedData = ms.ToArray();
ms.Close();
return Convert.ToBase64String(encryptedData);
}
public string Decrypt(string encryptedText)
{
// 復号化する
byte[] encryptedData = Convert.FromBase64String(encryptedText);
TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider();
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms,
des.CreateEncryptor(desKey, desIV),
CryptoStreamMode.Write);
cs.Write(encryptedData, 0, encryptedData.Length);
cs.Close();
byte[] destination = ms.ToArray();
ms.Close();
return Encoding.Unicode.GetString(destination);
}
} Program.cs class Program
{
static void Main(string[] args)
{
string plainText = "暗号化する文字列";
TripleDES tDES = new TripleDES();
// 暗号化する
string encryptedText = tDES.Encrypt(plainText);
// 暗号化文字列の表示
Console.WriteLine(encryptedText);
// :
// :
// 復号化する
string decryptedText = tDES.Decrypt(encryptedData);
// 復号化文字列の表示
Console.WriteLine(decryptedText);
}
}
|
|
この例では、比較的単純でクラスも3つ(TripleDESCryptoServiceProvider、 |
Façade パターンでは、複雑な手順は、 「窓口」となるクラスを作ってその中に入れたため、シンプルに利用できるようになりました。 |
|
Façadeパターンを使用しない例 Program.vb Imports System.Security.Cryptography
Imports System.IO
Imports System.Text
Module Main
Sub Main()
Dim planeText As String = "暗号化する文字列"
Dim des As TripleDESCryptoServiceProvider = New TripleDESCryptoServiceProvider()
Dim desKey As Byte() = des.Key ' 暗号化キー
Dim desIV As Byte() = des.IV ' 初期化ベクタ
' 暗号化する
Dim source As Byte() = Encoding.Unicode.GetBytes(planeText)
Dim ms As MemoryStream = New MemoryStream()
Dim cs As CryptoStream = New CryptoStream(ms,
des.CreateEncryptor(desKey, desIV),
CryptoStreamMode.Write)
cs.Write(source, 0, source.Length)
cs.Close()
Dim destination As Byte() = ms.ToArray()
ms.Close()
Dim encryptedText As String = Convert.ToBase64String(destination)
' 復号化する
source = Convert.FromBase64String(encryptedText)
ms = New MemoryStream()
cs = New CryptoStream(ms,
des.CreateDecryptor(desKey, desIV),
CryptoStreamMode.Write)
cs.Write(source, 0, source.Length)
cs.Close()
destination = ms.ToArray()
ms.Close()
Dim decryptedText As String = Encoding.Unicode.GetString(destination)
' 結果表示
Console.WriteLine(decryptedText)
End Sub
End Module
|
Façadeパターンを使用した例 TripleDES.vb Imports System.Security.Cryptography
Imports System.IO
Imports System.Text
Public Class TripleDES
Private des As TripleDESCryptoServiceProvider
Private desKey As Byte() ' 暗号化キー
Private desIV As Byte() ' 初期化ベクタ
Public Sub New()
des = New TripleDESCryptoServiceProvider()
desKey = des.Key ' 暗号化キー
desIV = des.IV ' 初期化ベクタ
End Sub
Public Function Encrypt(ByVal planeText As String) As String
' 暗号化する
Dim planeData As Byte() = Encoding.Unicode.GetBytes(planeText)
Dim des As TripleDESCryptoServiceProvider = New TripleDESCryptoServiceProvider()
Dim ms As MemoryStream = New MemoryStream()
Dim cs As CryptoStream = New CryptoStream(ms, des.CreateEncryptor(desKey, desIV),
CryptoStreamMode.Write)
cs.Write(planeData, 0, planeData.Length)
cs.Close()
Dim encryptedData As Byte() = ms.ToArray()
ms.Close()
Return Convert.ToBase64String(encryptedData)
End Function
Public Function Decrypt(ByVal encryptedText As String) As String
' 復号化する
Dim encryptedData As Byte() = Convert.FromBase64String(encryptedText)
Dim des As TripleDESCryptoServiceProvider = New TripleDESCryptoServiceProvider()
Dim ms As MemoryStream = New MemoryStream()
Dim cs As CryptoStream = New CryptoStream(ms, des.CreateDecryptor(desKey, desIV),
CryptoStream.Write)
cs.Write(encryptedData, 0, encryptedData.Length)
cs.Close()
Dim decryptedText As Byte() = ms.ToArray()
ms.Close()
Return Encoding.Unicode.GetString(decryptedText)
End Function
End Class
Program.vb Imports System.Text
Module Main
Sub Main()
Dim planeText As String = "暗号化する文字列"
Dim tDES As TripleDES = New TripleDES()
' 暗号化する
Dim encryptedText As String = tDES.Encrypt(planeText)
' 暗号化文字列の表示
Console.WriteLine(encryptedText)
' :
' :
' 復号化する
Dim decryptedText As String = tDES.Decrypt(encryptedData)
' 復号化文字列の表示
Console.WriteLine(decryptedText)
End Sub
End Module
|
|
この例では、比較的単純でクラスも3つ(TripleDESCryptoServiceProvider、 |
Façade パターンでは、複雑な手順は、 「窓口」となるクラスを作ってその中に入れたため、シンプルに利用できるようになりました。 |
|
Façadeパターンを使用しない例 Main.js const CryptoJS = require("./crypto-js.js");
// 対象文字列
let plainText = "暗号化する文字列";
// 暗号化キー
let key = "ABCDEFGHIJKLMNOP";
// 初期化ベクトル
let iv = CryptoJS.enc.Utf8.parse("1234567812345678");
// 暗号化する
let srcs = CryptoJS.enc.Utf8.parse(plainText);
let encrypt = CryptoJS.AES.encrypt(srcs, key,
{ iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
let encryptedData = encrypt.ciphertext.toString().toUpperCase();
let encryptedHexStr = CryptoJS.enc.Hex.parse(encryptedData);
let encryptedText = CryptoJS.enc.Base64.stringify(encryptedHexStr);
// 暗号化文字列の表示
process.stdout.write(encryptedText + "\n");
// :
// :
// 復号化する
let encryptedHexStr = CryptoJS.enc.Base64.parse(encryptedText);
let dencryptedData = CryptoJS.enc.Base64.stringify(encryptedHexStr);
let decrypt = CryptoJS.AES.decrypt(dencryptedData, key,
{ iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
let decryptedText = decrypt.toString(CryptoJS.enc.Utf8).toString();
// 復号化文字列の表示
process.stdout.write(decryptedText + "\n");
|
Façadeパターンを使用した例 AES.js const CryptoJS = require("./crypto-js.js");
module.exports = class AES {
static encrypt(plainText, key, iv) {
let srcs = CryptoJS.enc.Utf8.parse(plainText);
let encrypt = CryptoJS.AES.encrypt(srcs, key,
{ iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
let encryptedData = encrypt.ciphertext.toString().toUpperCase();
let encryptedHexStr = CryptoJS.enc.Hex.parse(encryptedData);
return CryptoJS.enc.Base64.stringify(encryptedHexStr);
}
static decrypt(encryptedText, key, iv) {
let encryptedHexStr = CryptoJS.enc.Base64.parse(encryptedText);
let dencryptedData = CryptoJS.enc.Base64.stringify(encryptedHexStr);
let decrypt = CryptoJS.AES.decrypt(srcs, key,
{ iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
let decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
return decryptedStr.toString();
}
}
Main.js const CryptoJS = require("./crypto-js.js");
const AES = require("./AES.js");
// 対象文字列
let plainText = "暗号化する文字列";
// 暗号化キー
let key = CryptoJS.enc.Utf8.parse("ABCDEFGHIJKLMNOP");
// initialization vector
let iv = CryptoJS.enc.Utf8.parse("1234567812345678");
//暗号化する
let encryptedText = AES.encrypt(plainText, key, iv);
// 暗号化文字列の表示
process.stdout.write(encryptedText + "\n");
// :
// :
//復号化する
let decryptedText = AES.decrypt(encryptedText, key, iv);
// 結果表示
process.stdout.write(decryptedText + "\n");
|
|
この例では、比較的単純でクラスも1つ(CryptoJS)しか利用していません。それでも、どのようにインスタンスを生成して、メソッドは何を呼んで、引数は何で...と、手順を踏まなければなりません。もしこれがいつも決まりきった手順なら、あらかじめ用意しておけばよいのです。 |
Façadeパターンでは、複雑な手順は、「窓口」となるクラスを作ってその中に入れたため、シンプルに利用できるようになりました。 |
|
Façadeパターンを使用しない例 Main.pl # 対象文字列
my plainText = "暗号化する文字列";
# 暗号化キー
my key = "ABCDEFGHIJKLMNOP";
sub _enc {
my ($i, $size, $o, $k) = @_;
my @key = @{$k};
my $mm = reverse map{($i, $m) = ($i/$size, $i%$size); $key[$m]} 1..$o;
my $ret = join '', $mm;
return $ret;
}
# 暗号化する
my @a = unpack('C*', $plainText);
my @keys = split('', $key);
my $size = @keys;
my $o = log(256)/log($size);
my %e = map{$_ => ':'._enc($_, $size, $o, \@keys);} 0..255;
my $encryptedData = join '', map{$e{$_}} @a;
# 暗号化文字列の表示
print $encryptedData . "\n";
# :
# :
# 復号化する
my @s = $encryptedData =~ /(:\w+)/g;
my %d = map{$e{$_} => $_ } keys %e;
my $decryptedStr = pack 'C*', map{$d{$_}} @s;
# 復号化文字列の表示
print decryptedText . "\n";
|
Façadeパターンを使用した例 MyCrypto.pm package MyCrypto {
my $DELIM = ":";
sub new {
my ($class, $key) = @_;
my @keys = split('', $key);
my $size = @keys;
my $o = log(256)/log($size);
my %e = map{$_ => $DELIM . _enc($_, $size, $o, \@keys);} 0..255;
my $this = { e => \%e };
return bless $this, $class;
}
sub encrypt {
my ($this, $plainText) = @_;
my @a = unpack('C*', $plainText);
my $e = $this->{e};
return join '', map{${$e}{$_}} @a;
}
sub decrypt {
my ($this, $encryptedData) = @_;
my @s = $encryptedData =~ /(${DELIM}\w+)/g;
my $e = $this->{e};
my %d = map{${$e}{$_} => $_ } keys %{$e};
return pack 'C*', map{$d{$_}} @s;
}
sub _enc {
my ($i, $size, $o, $k) = @_;
my @key = @{$k};
my $mm = reverse map{($i, $m) = ($i/$size, $i%$size); $key[$m]} 1..$o;
my $ret = join '', $mm;
return $ret;
}
}
1;
Main.pl use lib qw(./);
use MyCrypto;
# 対象文字列
my $plainText = "暗号化する文字列";
# 暗号化キー
my $key = "ABCDEFGHIJKLMNOP";
my $crypto = new MyCrypto($key);
print $encryptedData . "\n";
# 暗号化する
my $encryptedData = $crypto->encrypt($plainText);
# 暗号化文字列の表示
print $encryptedData . "\n";
# :
# :
# 復号化する
my $decryptedText = $crypto->decrypt($encryptedData);
# 復号化文字列の表示
print $decryptedText . "\n";
|
|
この例では、比較的単純な暗号です。それでも、どのような関数を呼んで、引数は何で...と、手順を踏まなければなりません。もしこれがいつも決まりきった手順なら、あらかじめ用意しておけばよいのです。 |
Façadeパターンでは、複雑な手順は、「窓口」となるクラスを作ってその中に入れたため、シンプルに利用できるようになりました。 |
|
Façadeパターンを使用しない例 Main.rb require 'openssl'
require 'base64'
# 対象文字列
plainText = "暗号化する文字列"
# 32byte共有鍵
key = "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"
# 16byte初期化ベクトル
iv = "1234567812345678"
# 暗号化する
enc = OpenSSL::Cipher.new('AES-256-CBC')
enc.encrypt
enc.key = key
enc.iv = iv
encryptedData = enc.update(plainText) + enc.final
encryptedText = Base64.encode64(encryptedData)
# 暗号化文字列の表示
puts encryptedText
# :
# :
# 復号化する
dec = OpenSSL::Cipher.new('AES-256-CBC')
dec.decrypt
dec.key = key
dec.iv = iv
decryptedData = Base64.decode64(encryptedText)
decryptedText = dec.update(decryptedData) + dec.final
# 復号化文字列の表示
puts decryptedText
|
Façadeパターンを使用した例 AES.rb require 'openssl'
require 'base64'
class AES
def AES.encrypt(plainText, key, iv)
enc = OpenSSL::Cipher.new('AES-256-CBC')
enc.encrypt
enc.key = key
enc.iv = iv
encryptedData = enc.update(plainText) + enc.final
return Base64.encode64(encryptedData)
end
def AES.decrypt(encryptedText, key, iv)
dec = OpenSSL::Cipher.new('AES-256-CBC')
dec.decrypt
dec.key = key
dec.iv = iv
decryptedData = Base64.decode64(encryptedText)
return dec.update(decryptedData) + dec.final
end
end
Main.rb require './AES'
# 対象文字列
plainText = "暗号化する文字列"
# 32byte共有鍵
key = "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"
# 16byte初期化ベクトル
iv = "1234567812345678"
# 暗号化する
encryptedText = AES.encrypt(plainText, key, iv)
# 暗号化文字列の表示
puts encryptedText
# :
# :
# 復号化する
decryptedText = AES.decrypt(encryptedText, key, iv)
# 復号化文字列の表示
puts decryptedText
|
|
この例では、比較的単純でクラスも1つ(Cipher)しか利用していません。それでも、どのようにインスタンスを生成して、メソッドは何を呼んで、引数は何で...と、手順を踏まなければなりません。もしこれがいつも決まりきった手順なら、あらかじめ用意しておけばよいのです。 |
Façadeパターンでは、複雑な手順は、「窓口」となるクラスを作ってその中に入れたため、シンプルに利用できるようになりました。 |
|
Façadeパターンを使用しない例 Main.py import base64
from Crypto.Cipher import AES
def __pad(s):
bs = 16
return s + (bs - len(s) % bs) * chr(bs - len(s) % bs)
def __unpad(s):
return s[:-ord(s[len(s)-1:])]
# 対象文字列
plainText = __pad("暗号化する文字列").encode()
# 暗号化キー
key = "ABCDEFGHIJKLMNOP".encode()
# 初期化ベクトル
iv = "1234567812345678".encode()
# 暗号化する
cipher = AES.new(key, AES.MODE_CBC, iv)
srcs = cipher.encrypt(plainText)
encryptedText = base64.b64encode(srcs)
# 暗号化文字列の表示
print(encryptedText)
# :
# :
# 復号化する
cipher = AES.new(key, AES.MODE_CBC, iv)
enc = base64.b64decode(encryptedData)
decryptedText = __unpad(cipher.decrypt(enc).decode())
# 復号化文字列の表示
print(decryptedText)
|
Façadeパターンを使用した例 MyCrypto.py import base64
from Crypto.Cipher import AES
class MyCrypto:
@staticmethod
def __pad(s):
bs = 16
return s + (bs - len(s) % bs) * chr(bs - len(s) % bs)
@staticmethod
def __unpad(s):
return s[:-ord(s[len(s)-1:])]
@staticmethod
def encrypt(plainText, key, iv):
plainText = MyCrypto.__pad(plainText).encode()
key = key.encode()
iv = iv.encode()
cipher = AES.new(key, AES.MODE_CBC, iv)
srcs = cipher.encrypt(plainText)
return base64.b64encode(srcs)
@staticmethod
def decrypt(encryptedText, key, iv):
key = key.encode()
iv = iv.encode()
cipher = AES.new(key, AES.MODE_CBC, iv)
enc = base64.b64decode(encryptedText)
return MyCrypto.__unpad(cipher.decrypt(enc).decode())
Main.py from MyCrypto import MyCrypto
# 対象文字列
plainText = "暗号化する文字列"
# 暗号化キー
key = "ABCDEFGHIJKLMNOP"
# 初期化ベクトル
iv = "1234567812345678"
# 暗号化する
encryptedText = MyCrypto.encrypt(plainText, key, iv)
# 暗号化文字列の表示
print(encryptedText)
# :
# :
# 復号化する
decryptedText = MyCrypto.decrypt(encryptedText, key, iv)
# 復号化文字列の表示
print(decryptedText)
|
|
この例では、比較的単純でクラスも1つ(AES)しか利用していません。それでも、どのようにインスタンスを生成して、メソッドは何を呼んで、引数は何で...と、手順を踏まなければなりません。もしこれがいつも決まりきった手順なら、あらかじめ用意しておけばよいのです。 |
Façadeパターンでは、複雑な手順は、「窓口」となるクラスを作ってその中に入れたため、シンプルに利用できるようになりました。 |
|
Façadeパターンを使用しない例 Main.java <?php
// 対象文字列
$plainText = "暗号化する文字列";
// 暗号化キー
$key = "ABCDEFGHIJKLMNOP";
// 初期化ベクトル
$iv = "1234567812345678";
// 暗号化する
$salt = openssl_random_pseudo_bytes(16);
$encrypted = openssl_encrypt($plainText, 'AES-256-CBC', $key, 0, $iv);
$encryptedText = base64_encode($salt . $encrypted);
// 暗号化文字列の表示
print $encryptedText . "\n";
// :
// :
// 復号化する
$data = base64_decode($encryptedText);
$ct = substr($data, 16);
$decryptedText = openssl_decrypt($ct, 'AES-256-CBC', $key, 0, $iv);
// 復号化文字列の表示
print $decryptedText . "\n";
?>
|
Façadeパターンを使用した例 AES.java <?php
class AES {
public static function encrypt($plainText, $key, $iv) {
$salt = openssl_random_pseudo_bytes(16);
$encrypted = openssl_encrypt($plainText, 'AES-256-CBC', $key, 0, $iv);
return base64_encode($salt . $encrypted);
}
public static function decrypt($encryptedText, $key, $iv) {
$data = base64_decode($encryptedText);
$ct = substr($data, 16);
return openssl_decrypt($ct, 'AES-256-CBC', $key, 0, $iv);
}
}
?>
Main.java <?php
require_once('AES.php');
// 対象文字列
$plainText = "暗号化する文字列";
// 暗号化キー
$key = "ABCDEFGHIJKLMNOP";
// 初期化ベクトル
$iv = "1234567812345678";
//暗号化する
$encryptedText = AES::encrypt($plainText, $key, $iv);
// 暗号化文字列の表示
print $encryptedText . "\n";
// :
// :
//復号化する
$decryptedText = AES::decrypt($encryptedText, $key, $iv);
// 復号化文字列の表示
print $decryptedText . "\n";
?>
|
|
この例では、比較的単純な暗号です。それでも、どのような関数を呼んで、引数は何で...と、手順を踏まなければなりません。もしこれがいつも決まりきった手順なら、あらかじめ用意しておけばよいのです。 |
Façadeパターンでは、複雑な手順は、「窓口」となるクラスを作ってその中に入れたため、シンプルに利用できるようになりました。 |
|
Façadeパターンを使用しない例 Main.ts import { TripleDES, mode, pad, enc } from "crypto-js";
// 対象文字列
let plainText:string = "暗号化する文字列";
// 暗号化キー
let key:any = enc.Utf8.parse("ABCDEFGHIJKLMNOP");
// initialization vector
let iv:any = enc.Utf8.parse("1234567812345678");
// 暗号化する
let srcs:any = enc.Utf8.parse(plainText);
let encrypt:any = TripleDES.encrypt(srcs, key, { iv: iv, mode: mode.CBC, padding: pad.Pkcs7 });
let encryptedData:string = encrypt.ciphertext.toString().toUpperCase();
let encryptedText:string = Buffer.from(encryptedData).toString("base64");
// 暗号化文字列の表示
process.stdout.write(encryptedText + "\n");
// :
// :
// 復号化する
let encryptedHexStr:string = Buffer.from(encryptedText, "base64").toString();
let encryptedHexData:any = enc.Hex.parse(encryptedHexStr);
let decryptedData:any = enc.Base64.stringify(encryptedHexData);
let decrypt:any = TripleDES.decrypt(decryptedData, key, { iv: iv, mode: mode.CBC, padding: pad.Pkcs7 });
let decryptedText:string = decrypt.toString(enc.Utf8).toString();
// 復号化文字列の表示
process.stdout.write(decryptedText + "\n");
|
Façadeパターンを使用した例 AES.ts import { TripleDES, mode, pad, enc } from "crypto-js";
export
class AES {
public static encrypt(plainText:string, key:string, iv:any):string {
let srcs:any = enc.Utf8.parse(plainText);
let keyu:any = enc.Utf8.parse(key);
let ivu:any = enc.Utf8.parse(iv);
let encrypted:any = TripleDES.encrypt(srcs, keyu, { iv: ivu, mode: mode.CBC, padding: pad.Pkcs7 });
let encryptedData:string = encrypted.ciphertext.toString().toUpperCase();
return Buffer.from(encryptedData).toString("base64");
}
public static decrypt(encryptedText:string, key:string, iv:any):string {
let encryptedHexStr:string = Buffer.from(encryptedText, "base64").toString();
let keyu:any = enc.Utf8.parse(key);
let ivu:any = enc.Utf8.parse(iv);
let encryptedHexData:any = enc.Hex.parse(encryptedText);
let decryptedData:string = enc.Base64.stringify(encryptedHexData);
let decrypt:any = TripleDES.decrypt(decryptedData, keyu, { iv: ivu, mode: mode.CBC, padding: pad.Pkcs7 });
return decrypt.toString(enc.Utf8).toString();
}
} Main.ts import {AES} from "./AES";
// 対象文字列
let plainText:string = "暗号化する文字列";
// 暗号化キー
let key:string = "ABCDEFGHIJKLMNOP";
// initialization vector
let iv:string = "1234567812345678";
//暗号化する
let encryptedText:string = AES.encrypt(plainText, key, iv);
//暗号化文字列の表示
process.stdout.write(encryptedText + "\n");
// :
// :
//復号化する
let decryptedText:string = AES.decrypt(encryptedText, key, iv);
// 復号化文字列の表示
process.stdout.write(decryptedText + "\n");
|
|
この例では、比較的単純でクラスも1つ(TripleDES)しか利用していません。それでも、どのようにインスタンスを生成して、メソッドは何を呼んで、引数は何で...と、手順を踏まなければなりません。もしこれがいつも決まりきった手順なら、あらかじめ用意しておけばよいのです。 |
Façadeパターンでは、複雑な手順は、「窓口」となるクラスを作ってその中に入れたため、シンプルに利用できるようになりました。 |
|
Façadeパターンを使用しない例 Main.swift import Foundation
import CryptoSwift
// 対象文字列
let plainText:String = "暗号化する文字列"
// 暗号化キー
let key:String = "ABCDEFGHIJKLMNOP"
// 初期化ベクトル
let iv:String = "1234567812345678"
// 暗号化する
let encryptedText:String
do {
let aes:AES = try AES(key: key, iv: iv)
let encrypted:[UInt8] = try aes.encrypt(Array(plainText.utf8))
let encryptedData:Data = NSData(bytes:encrypted, length:encrypted.count).base64EncodedData(options:[])
guard let strEnc:String = String(data:encryptedData, encoding:.utf8) else {
fatalError("エラー")
}
encryptedText = strEnc
}
catch {
fatalError("エラー")
}
//暗号化文字列の表示
print(encryptedText)
// :
// :
// 復号化する
let decryptedText:String
do {
let aes:AES = try AES(key: key, iv: iv)
let aData:Data = encryptedText.data(using:.utf8)! as Data
let dData:NSData = NSData(base64Encoded:aData, options:[])!
var aBuffer:[UInt8] = Array<UInt8>(repeating:0, count:dData.length)
dData.getBytes(&aBuffer, length:dData.length)
let decrypted = try aes.decrypt(aBuffer)
guard let strDec:String = String(data: Data(_:decrypted), encoding:.utf8)
else { fatalError("エラー") }
decryptedText = strDec
}
catch {
fatalError("エラー")
}
// 復号化文字列の表示
print(decryptedText)
|
Façadeパターンを使用した例 MyCrypto.swift import Foundation
import CryptoSwift
public class MyCrypto {
public static func encrypt(_ plainText:String, _ key:String, _ iv:String) -> String {
// 暗号化する
do {
let aes:AES = try AES(key: key, iv: iv)
let encrypted:[UInt8] = try aes.encrypt(Array(plainText.utf8))
let encryptedData:Data = NSData(bytes:encrypted, length:encrypted.count)
.base64EncodedData(options:[])
guard let encryptedText:String = String(data:encryptedData, encoding:.utf8)
else { fatalError("エラー") }
return encryptedText
}
catch {
fatalError("エラー")
}
}
public static func decrypt(_ encryptedText:String, _ key:String, _ iv:String) -> String {
// 復号化する
do {
let aes:AES = try AES(key: key, iv: iv)
let aData:Data = encryptedText.data(using:.utf8)! as Data
let dData:NSData = NSData(base64Encoded:aData, options:[])!
var aBuffer:[UInt8] = Array<UInt8>(repeating:0, count:dData.length)
dData.getBytes(&aBuffer, length:dData.length)
let decrypted = try aes.decrypt(aBuffer)
guard let decryptedText:String = String(data: Data(_:decrypted), encoding:.utf8)
else { fatalError("エラー") }
return decryptedText
}
catch {
fatalError("エラー")
}
}
}
Main.ts // 対象文字列
let plainText:String = "暗号化する文字列"
// 暗号化キー
let key:String = "ABCDEFGHIJKLMNOP"
// initialization vector
let iv:String = "1234567812345678"
//暗号化する
let encryptedText:String = MyCrypto.encrypt(plainText, key, iv)
//暗号化文字列の表示
print(encryptedText)
// :
// :
//復号化する
let decryptedText:String = MyCrypto.decrypt(encryptedText, key, iv)
// 復号化文字列の表示
print(decryptedText)
|
|
この例では、比較的単純な暗号です。それでも、どのようにインスタンスを生成して、メソッドは何を呼んで、引数は何で...と、手順を踏まなければなりません。もしこれがいつも決まりきった手順なら、あらかじめ用意しておけばよいのです。 |
Façadeパターンでは、複雑な手順は、「窓口」となるクラスを作ってその中に入れたため、シンプルに利用できるようになりました。 |
|
Façadeパターンを使用しない例 Main.kt import java.util.*
import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec
fun main() {
// 対象文字列
val plainText = "暗号化する文字列"
// 暗号化キー
val encryptingKey = "ABCDEFGHIJKLMNOP"
// 暗号化する
val secretKey = SecretKeySpec(encryptingKey.toByteArray(), "AES")
val cipher = Cipher.getInstance("AES")
cipher.init(Cipher.ENCRYPT_MODE, secretKey)
var encryptedData = cipher.doFinal(plainText.toByteArray())
val encryptedText = String(Base64.getEncoder().encode(encryptedData))
// 暗号化文字列の表示
println(encryptedText)
// :
// :
// 復号化する
cipher.init(Cipher.DECRYPT_MODE, secretKey)
encryptedData = Base64.getDecoder().decode(encryptedText)
val decryptedData = cipher.doFinal(decryptedData)
val decryptedText = String(decryptedData)
// 復号化文字列の表示
println(decryptedText)
}
|
Façadeパターンを使用した例 AES.kt import java.util.Base64
import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec
object AES {
fun encrypt(plainText: String, encryptingKey: String) : String {
val secretKey = SecretKeySpec(encryptingKey.toByteArray(), "AES")
val cipher = Cipher.getInstance("AES")
// 暗号化する
cipher.init(Cipher.ENCRYPT_MODE, secretKey)
val encryptedData = cipher.doFinal(plainText.toByteArray())
return String(Base64.getEncoder().encode(encryptedData))
}
public static decrypt(encryptedText: String, encryptingKey: String) : String {
val encryptedData: ByteArray = Base64.getDecoder().decode(encryptedText)
val secretKey = SecretKeySpec(encryptingKey.toByteArray(), "AES")
val cipher = Cipher.getInstance("AES")
//復号化する
cipher.init(Cipher.DECRYPT_MODE, secretKey)
val decryptedData = cipher.doFinal(encryptedData)
return String(decryptedData)
}
}
Main.kt fun main() {
// 対象文字列
val plainText = "暗号化する文字列"
// 暗号化キー
val encryptingKey = "ABCDEFGHIJKLMNOP"
//暗号化する
val encryptedText: String = AES.encrypt(plainText, encryptingKey)
//暗号化文字列の表示
println(encryptedText)
// :
// :
//復号化する
val decryptedText: String = AES.decrypt(encryptedText, encryptingKey)
// 復号化文字列の表示
println(decryptedText)
}
|
|
この例では、比較的単純でクラスも2つ(SecretKeySpec、Cipher)しか利用していません。それでも、どのようにインスタンスを生成して、メソッドは何を呼んで、引数は何で...と、手順を踏まなければなりません。もしこれがいつも決まりきった手順なら、あらかじめ用意しておけばよいのです。 |
Façadeパターンでは、複雑な手順は、「窓口」となるクラスを作ってその中に入れたため、シンプルに利用できるようになりました。 |
|
Façadeパターンを使用しない例 Main.scala import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec
import java.util.Base64
object Main {
def main(args: Array[String]) {
// 対象文字列
val plainText = "暗号化する文字列"
// 暗号化キー
val encryptingKey = "ABCDEFGHIJKLMNOP"
// 暗号化する
val secretKey = new SecretKeySpec(encryptingKey.getBytes, "AES")
val cipher = Cipher.getInstance("AES")
cipher.init(Cipher.ENCRYPT_MODE, secretKey)
var encryptedData = cipher.doFinal(plainText.getBytes)
val encryptedText = new String(Base64.getEncoder().encode(encryptedData))
// 暗号化文字列の表示
System.out.println(encryptedText)
// :
// :
// 復号化する
cipher.init(Cipher.DECRYPT_MODE, secretKey)
encryptedData = Base64.getDecoder().decode(encryptedText)
val decryptedData = cipher.doFinal(decryptedData)
val decryptedText = new String(decryptedData)
// 復号化文字列の表示
System.out.println(decryptedText)
}
}
|
Façadeパターンを使用した例 AES.scala import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec
import java.util.Base64
object AES {
def encrypt(plainText: String, encryptingKey: String) : String = {
val secretKey = SecretKeySpec(encryptingKey.toByteArray(), "AES")
val cipher = Cipher.getInstance("AES")
// 暗号化する
cipher.init(Cipher.ENCRYPT_MODE, secretKey)
val encryptedData = cipher.doFinal(plainText.getBytes)
new String(Base64.getEncoder().encode(encryptedData))
}
def decrypt(encryptedText: String, encryptingKey: String) : String = {
val encryptedData = Base64.getDecoder().decode(encryptedText)
val secretKey = new SecretKeySpec(encryptingKey.getBytes, "AES")
val cipher = Cipher.getInstance("AES")
//復号化する
cipher.init(Cipher.DECRYPT_MODE, secretKey)
val decryptedData = cipher.doFinal(encryptedData)
new String(decryptedData)
}
}
Main.scala object Main {
def main(args: Array[String]) {
// 対象文字列
val plainText = "暗号化する文字列"
// 暗号化キー
val encryptingKey = "ABCDEFGHIJKLMNOP"
//暗号化する
val encryptedText: String = AES.encrypt(plainText, encryptingKey)
//暗号化文字列の表示
System.out.println(encryptedText)
// :
// :
//復号化する
val decryptedText: String = AES.decrypt(encryptedText, encryptingKey)
// 復号化文字列の表示
System.out.println(decryptedText)
}
}
|
|
この例では、比較的単純でクラスも2つ(SecretKeySpec、Cipher)しか利用していません。それでも、どのようにインスタンスを生成して、メソッドは何を呼んで、引数は何で...と、手順を踏まなければなりません。もしこれがいつも決まりきった手順なら、あらかじめ用意しておけばよいのです。 |
Façadeパターンでは、複雑な手順は、「窓口」となるクラスを作ってその中に入れたため、シンプルに利用できるようになりました。 |
|
Façadeパターンを使用しない例 Main.groovy import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec
class Main {
static void main(String[] args) {
// 対象文字列
String plainText = "暗号化する文字列"
// 暗号化キー
String encryptingKey = "ABCDEFGHIJKLMNOP"
// 暗号化する
SecretKeySpec secretKey = new SecretKeySpec(encryptingKey.getBytes(), "AES")
Cipher cipher = Cipher.getInstance("AES")
cipher.init(Cipher.ENCRYPT_MODE, secretKey)
byte[] encryptedData = cipher.doFinal(plainText.getBytes())
String encryptedText = new String(Base64.getEncoder().encode(encryptedData))
//暗号化文字列の表示
System.out.println(encryptedText)
// :
// :
// 復号化する
cipher.init(Cipher.DECRYPT_MODE, secretKey)
encryptedData = Base64.getDecoder().decode(encryptedText)
byte[] decryptedData = cipher.doFinal(encryptedData)
String decryptedText = new String(decryptedData)
// 結果表示
System.out.println(decryptedText)
}
}
|
Façadeパターンを使用した例 AES.groovy import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec
class AES {
static String encrypt(String plainText, String encryptingKey) throws Exception {
SecretKeySpec secretKey = new SecretKeySpec(encryptingKey.getBytes(), "AES")
Cipher cipher = Cipher.getInstance("AES")
// 暗号化する
cipher.init(Cipher.ENCRYPT_MODE, secretKey)
byte[] encryptedData = cipher.doFinal(plainText.getBytes())
return new String(Base64.getEncoder().encode(encryptedData))
}
static String decrypt(String encryptedText, String encryptingKey) throws Exception {
byte[] encryptedData = Base64.getDecoder().decode(encryptedText)
SecretKeySpec secretKey = new SecretKeySpec(encryptingKey.getBytes(), "AES")
Cipher cipher = Cipher.getInstance("AES")
//復号化する
cipher.init(Cipher.DECRYPT_MODE, secretKey)
byte[] decryptedData = cipher.doFinal(encryptedData)
return new String(decryptedData)
}
}
Main.groovy public class Main {
static void main(String[] args) {
// 対象文字列
String plainText = "暗号化する文字列"
// 暗号化キー
String encryptingKey = "ABCDEFGHIJKLMNOP"
//暗号化する
String encryptedText = AES.encrypt(plainText, encryptingKey)
//暗号化文字列の表示
System.out.println(encryptedText)
// :
// :
//復号化する
String decryptedText = AES.decrypt(encryptedText, encryptingKey)
// 復号化文字列の表示
System.out.println(decryptedText)
}
}
|
|
この例では、比較的単純でクラスも2つ(SecretKeySpec、Cipher)しか利用していません。それでも、どのようにインスタンスを生成して、メソッドは何を呼んで、引数は何で...と、手順を踏まなければなりません。もしこれがいつも決まりきった手順なら、あらかじめ用意しておけばよいのです。 |
Façadeパターンでは、複雑な手順は、「窓口」となるクラスを作ってその中に入れたため、シンプルに利用できるようになりました。 |
|
Façadeパターンを使用しない例 Main.go import (
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"fmt"
"os"
)
func main() {
// 対象文字列
var plainText = "暗号化する文字列"
// 暗号化キー
var key = "ABCDEFGHIJKLMNOP"
// initialization vector
var iv = []byte("1234567812345678")
// 暗号化アルゴリズム AES を作成
var c, err = aes.NewCipher([]byte(key))
if err != nil {
fmt.Printf("Error: NewCipher(%d bytes) = %s", len(key), err)
os.Exit(-1)
}
// 暗号化する
var cfb = cipher.NewCFBEncrypter(c, iv)
var plainData = []byte(plainText)
var encryptedData = make([]byte, len(plainData))
cfb.XORKeyStream(encryptedData, plainData)
var encryptedText = base64.StdEncoding.EncodeToString(encryptedData)
//暗号化文字列の表示
fmt.Println(encryptedText)
// :
// :
// 復号化する
encryptedData, _ = base64.StdEncoding.DecodeString(encryptedText)
var cfbdec = cipher.NewCFBDecrypter(c, iv)
var plainTextCopy = make([]byte, len(encryptedData))
cfbdec.XORKeyStream(plainTextCopy, encryptedData)
var decryptedText = string(plainTextCopy)
// 結果表示
fmt.Println(decryptedText)
}
|
Façadeパターンを使用した例 AES.go import (
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"fmt"
"os"
)
type AES struct {}
func (self *AES) Encrypt(plainText string, key string, iv string) (string, bool) {
// 暗号化アルゴリズム AES を作成
var c, err = aes.NewCipher([]byte(key))
if err != nil {
return fmt.Sprintf("Error:%s", err), false
}
// 暗号化する
var cfb = cipher.NewCFBEncrypter(c, []byte(iv))
var plainData = []byte(plainText)
var encryptedData = make([]byte, len(plainData))
cfb.XORKeyStream(encryptedData, plainData)
var ncryptedText = base64.StdEncoding.EncodeToString(encryptedData)
return encryptedText, true
}
func (self *AES) Decrypt(encryptedText string, key string, iv string) (string, bool) {
// 暗号化アルゴリズム AES を作成
var c, err = aes.NewCipher([]byte(key))
if err != nil {
return fmt.Sprintf("Error:%s", err), false
}
// 復号化する
var encryptedData, _ = base64.StdEncoding.DecodeString(encryptedText)
var cfbdec = cipher.NewCFBDecrypter(c, []byte(iv))
var plainTextCopy = make([]byte, len(encryptedData))
cfbdec.XORKeyStream(plainTextCopy, encryptedData)
var decryptedText = string(plainTextCopy)
return decryptedText, true
}
Main.go func main() {
// 対象文字列
var plainText = "暗号化する文字列"
// 暗号化キー
var key = "ABCDEFGHIJKLMNOP"
// initialization vector
var iv = "1234567812345678"
var aes = AES{}
//暗号化する
var encryptedText, _ = aes.Encrypt(plainText, key, iv)
//暗号化文字列の表示
fmt.Println(encryptedText)
// :
// :
//復号化する
var decryptedText, _ = aes.Decrypt(encryptedText, key, iv)
// 復号化文字列の表示
fmt.Println(decryptedText)
}
|
|
この例では比較的単純ですが、それでもどのようにインスタンスを生成して、メソッドは何を呼んで、引数は何で...と、手順を踏まなければなりません。もしこれがいつも決まりきった手順なら、あらかじめ用意しておけばよいのです。 |
Façadeパターンでは、複雑な手順は、「窓口」となるクラスを作ってその中に入れたため、シンプルに利用できるようになりました。 |
|
Façadeパターンを使用しない例 main.d import crypto.aes; // https://code.dlang.org/packages/crypto を参考にしました
import crypto.padding;
import crypto.base58;
public int main() {
// 対象文字列
string plainText = "暗号化する文字列";
// 暗号化キー
string encryptingKey = "ABCDEFGHIJKLMNOP";
// initialization vector
ubyte[] iv = [1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8];
// 暗号化する
ubyte[] encryptedData = cast(ubyte[])AESUtils.encrypt!AES128(
cast(ubyte[])plainText, encryptingKey, iv, PaddingMode.PKCS5);
string encryptedText = Base58.encode(cast(byte[])encryptedData);
//暗号化文字列の表示
printfln(encryptedText);
// :
// :
// 復号化する
encryptedData = cast(ubyte[])Base58.decode(cast(char[])encryptedText);
ubyte[] decryptedData = AESUtils.decrypt!AES128(
cast(ubyte[])encryptedData, encryptingKey, iv, PaddingMode.PKCS5);
string decryptedText = cast(string)(decryptedData);
// 結果表示
printflf(decryptedText);
}
private void printfln(T...)(T args) { // Shift JIS 出力
import std, std.windows.charset, core.vararg;
std.stdio.write(to!(string)(toMBSz(std.format.format(args))) ~ "\n");
}
|
Façadeパターンを使用した例 mycrypto.d import crypto.aes; // https://code.dlang.org/packages/crypto を参考にしました
import crypto.padding;
import crypto.base58;
public class MyCrypto {
public static string encrypt(in string plainText, in string encryptingKey, in ubyte[] iv) {
// 暗号化する
ubyte[] encryptedData = cast(ubyte[])AESUtils.encrypt!AES128(
cast(ubyte[])plainText, encryptingKey, iv, PaddingMode.PKCS5);
return Base58.encode(cast(byte[])encryptedData);
}
public static String decrypt(in string encryptedText, in string encryptingKey, in ubyte[] iv) {
//復号化する
ubyte[] encryptedData = cast(ubyte[])Base58.decode(cast(char[])encryptedText);
ubyte[] decryptedData = AESUtils.decrypt!AES128(
cast(ubyte[])encryptedData, encryptingKey, iv, PaddingMode.PKCS5);
return cast(string)(decryptedData);
}
}
main.d import mycrypto;
int main() {
// 対象文字列
string plainText = "暗号化する文字列";
// 暗号化キー
string encryptingKey = "ABCDEFGHIJKLMNOP";
// initialization vector
ubyte[] iv = [1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8];
//暗号化する
String encryptedText = MyCrypto.encrypt(plainText, encryptingKey, iv);
//暗号化文字列の表示
printfln(encryptedText);
// :
// :
//復号化する
String decryptedText = MyCrypto.decrypt(encryptedText, encryptingKey, iv);
// 復号化文字列の表示
printfln(decryptedText);
}
private void printfln(T...)(T args) { // Shift JIS 出力
import std, std.windows.charset, core.vararg;
std.stdio.write(to!(string)(toMBSz(std.format.format(args))) ~ "\n");
}
|
|
この例では、比較的単純でクラスも2つ(AESUtils、Base58)しか利用していません。それでも、どのようにインスタンスを生成して、メソッドは何を呼んで、引数は何で...と、手順を踏まなければなりません。もしこれがいつも決まりきった手順なら、あらかじめ用意しておけばよいのです。 |
Façadeパターンでは、複雑な手順は、「窓口」となるクラスを作ってその中に入れたため、シンプルに利用できるようになりました。 |
|
Façadeパターンを使用しない例 Main.dpr program FacadeNon;
uses
Mam.AES, // https://mam-mam.net/delphi/aes_encrypt_decrypt_unit.html を参考にしました
System.SysUtils,
EncdDecd,
System.NetEncoding;
var
aes:TMamAes;
plainText:string;
encryptingKey:string;
decryptedData, encryptedData:TBytes;
decryptedText:string;
encryptedText:String;
begin
aes := TMamAes.Create(TmamAesType.MamAES128CBC);
plainText := '暗号化する文字列';
encryptingKey := 'ABCDEFGHIJKLMNOP';
//暗号化を行う
encryptedData := TEncoding.UTF8.GetBytes(plainText);
encryptedData := aes.OpenSslEncrypt(encryptedData, encryptingKey);
encryptedText := EncodeBase64(encryptedData , Length(encryptedData));
//暗号化文字列の表示
Writeln(encryptedText);
// :
// :
//復号化を行う
encryptedData := DecodeBase64(encryptedText);
encryptedData := aes.OpenSslDecrypt(encryptedData, encryptingKey);
decryptedText := TEncoding.UTF8.GetString(decryptedData);
// 結果表示
Writeln(decryptedText);
aes.Free;
end.
|
Façadeパターンを使用した例 AES.java unit UnitAES;
interface
uses
Mam.AES,
System.SysUtils,
EncdDecd,
System.NetEncoding;
type
AES = class
public
class function encrypt(plainText:string; encryptingKey:string):string;
class function decrypt(encryptedText:string; encryptingKey:string):string;
end;
implementation
class function AES.encrypt(plainText:string; encryptingKey:string):string;
var aes:TMamAes;
var encryptedData:TBytes;
var encryptedText:string;
begin
//暗号化を行う
aes := TMamAes.Create(TmamAesType.MamAES128CBC);
encryptedData := TEncoding.UTF8.GetBytes(plainText);
encryptedData := aes.OpenSslEncrypt(encryptedData, encryptingKey);
aes.Free;
Result := EncodeBase64(encryptedData , Length(encryptedData ));
end;
class function AES.decrypt(encryptedText:string; encryptingKey:string):string;
var aes:TMamAes;
var encryptedData:TBytes;
var decryptedData:TBytes;
begin
//復号化を行う
aes := TMamAes.Create(TmamAesType.MamAES128CBC);
encryptedData := DecodeBase64(encryptedText);
decryptedData := aes.OpenSslDecrypt(encryptedData, encryptingKey);
aes.Free;
Result := TEncoding.UTF8.GetString(decryptedData);
end;
end.
Main.dpr program FacadeGof;
uses
System.SysUtils,
UnitAES;
var plainText:string;
var encryptingKey:string;
var encryptedText:string;
var decryptedText:string;
begin
plainText :='暗号化する文字列';
encryptingKey := 'ABCDEFGHIJKLMNOP';
//暗号化を行う
encryptedText := AES.encrypt(plainText, encryptingKey);
//暗号化文字列の表示
Writeln(encryptedText);
// :
// :
//復号化を行う
decryptedText := AES.decrypt(encryptedText, encryptingKey);
// 復号化文字列の表示
Writeln(decryptedText);
end.
|
|
この例では、比較的単純ですが、それでもどのようにインスタンスを生成して、メソッドは何を呼んで、引数は何で...と、手順を踏まなければなりません。もしこれがいつも決まりきった手順なら、あらかじめ用意しておけばよいのです。 |
Façadeパターンでは、複雑な手順は、「窓口」となるクラスを作ってその中に入れたため、シンプルに利用できるようになりました。 |