Pythonロボティクスコース レッスン 41
テーマ.10-4 認証システムを搭載したゲートの制作
データを安全に扱うための暗号化やハッシュ化の技術を学ぼう
チャプター1
このレッスンで学ぶこと
このレッスンでは、ネットワーク上での情報のやり取りを安全に行うための技術である、データの「暗号化/復号」と「ハッシュ化」について学習します。
チャプター2
データの暗号化と復号
データの暗号化と複号は、ネットワーク上で、送信者と受信者の間で安全にデータをやり取りするために欠かせない情報技術のひとつです。
例えば、スマートフォンのアプリを使って誰かにメッセージや写真を送る場面では、これらのデータがネットワーク(インターネット回線)を通って相手の所へ届けられます。このときのメッセージや写真などのデータは、テーマ.10-2で学習したように「0」と「1」で表されるビット単位(またはバイト単位)のデータに変換されてネットワーク上を流れています。
ネットワークはクモの巣のように、様々な地点をつなぐようにして回線が張り巡らされています。各地点には、ネットワーク上の住所にあたる「IP※アドレス」が割り当てられていて、特定の誰かにデータを送るときは、自分のIPアドレスと相手先のIPアドレスをもとに、ネットワークの中から最適なルートが探索されて、複数の中継地点を通りながら情報が運ばれる仕組みになっています。
※ IP・・・Internet Protocolの略。インターネットにおける主要な通信規格。
そのため、ネットワークには常に誰かにデータを盗聴されてしまう危険性が付きまといます。バイト列に変換された数値や文字列のデータを簡単に元の形式に戻すことができたように、ネットワークへそのままデータを流してしまうと、盗まれたときに容易く解析されてしまいます。これによって、自分が送ったメッセージや写真を全く知らない人に見られてしまったり、盗まれた情報がネットワーク上に流されてしまったりする事態も起きてしまいます。
そこで、これらの問題を避けるために使われているのが暗号化と複号の技術です。送信者は、ネットワークへデータを流す前に、特定の鍵を使ってデータを暗号化します。暗号化されたデータは、鍵なしでは解読が困難なため、仮に盗まれてしまっても、元のデータを知られることがありません。そして、本来の受信者だけが同じく鍵を使ってデータの復号を行い、元のデータを確認することができます。
2. 1 暗号化と複号の方式
暗号化と復号の方式には、共通鍵暗号方式と公開鍵暗号方式の2つがあり、それぞれ次のような特徴があります。
■ 共通鍵暗号方式
- 暗号化と複合に同じ鍵(共通鍵)を使用する。
- 鍵交換は盗聴されないように安全な方法で行う必要がある。
■ 公開鍵暗号方式
- 暗号化用の鍵(公開鍵)と複合用の鍵(秘密鍵)を分けて使用する。
- 公開鍵で暗号化されたデータは、受信側のみがもつ秘密鍵でしか復号ができず、公開鍵のみを知る第三者がデータを復号することはできない。
2. 2 MicroPythonでのデータの暗号化と復号
Micropythonでは、ucryptolib
モジュールで暗号化と復号化のための機能が提供されています。ucryptolib
は、共通鍵暗号方式に対応していて、次の3つの暗号利用モードが選択できます。
- Electronic Codebook (ECB)
- Cipher Block Chaining (CBC)
- Counter (CTR)
暗号利用モードは簡単に言うと、「暗号化するための仕組み」のことです。暗号利用モードによって、セキュリティの高さや計算に掛かるコストが異なります。それぞれの暗号利用モードについて詳しく説明すると内容が長くなってしまうので、ここでは「Electronic Codebook (ECB)」と「Cipher Block Chaining (CBC)」の特徴を簡単に紹介します。
■ Electronic Codebook (ECB)
暗号利用モードの中でも最もシンプルなモードで、ブロックと呼ばれる単位でデータが暗号化される。セキュリティ能力は低い。
■ Cipher Block Chaining (CBC)
ECBよりもセキュリティ能力が高いモード。前のブロックを暗号化した結果を次のブロックの暗号化にも利用するため、複数のブロックが鎖(chain)のようにつながった形で表される。
暗号利用モードについて詳しく知りたい人は、以下のwikipediaのページを参考にしてください。
2. 3 データの暗号化と復号の実践
上で紹介した2つの暗号利用モードを比較すると「CBC」の方がより堅牢な暗号化処理だと言えます。そこでここからは、「CBC」を利用してデータの暗号化と複合を実践してみましょう。プログラムは、実際のネットワーク上でのデータの流れを意識して、送信側と受信側、そしてネットワークに分けてコードを書いていきます。
【 プログラムで定義する関数 】
関数名 | 内容 |
---|---|
encrypt_process | ターミナルから入力された16字以下のメッセージを暗号化して送る送信側のプロセス |
decrypt_process | 受け取ったメッセージを復号してターミナルに表示する受信側のプロセス |
network_process | メッセージの運搬を行うネットワークのプロセス |
■ 送信側のプロセスの作成
ucryptolib
モジュールのCBCモードで暗号化を行うためには、16バイトの共通鍵と初期ベクトルが必要です。初期ベクトルは、データ内で最初に暗号化するブロックに適用されるものです。最初のブロックは、2つめ以降のブロックと違い、前のブロックの暗号化されたデータが存在していないため、その代わりとして使われます。
共通鍵と初期ベクトルは、データ量が16バイトであれば、それぞれどんな文字列でも構いません。ここでは適当に決めた16字(1字につき1バイト)の英数字を共通鍵と初期ベクトルとして利用しましょう。
import ucryptolib
key = "abcdefghigklmnop" # 共通鍵(16バイト)
init_vector = "1234567891234567" # 初期ベクトル(16バイト)
次に暗号化・復号用のオブジェクトを作成します。これには、ucryptolib
モジュールのaes()
関数を使います。
aes(共通鍵、暗号利用モード、初期ベクトル※CBCの場合のみ)
この関数の第2引数には、使用する暗号利用モードによって以下の数値を指定します。
暗号利用モード | 第2引数に指定する数値 |
---|---|
Electronic Code Book (ECB) | 1 |
Cipher Block Chaining (CBC) | 2 |
Counter (CTR) | 6 |
この関数が返す暗号化・復号用オブジェクトがもつencrypt()
メソッドやdecrypt()
メソッドで暗号化(encrypt)と複号(decrypt)を行います。一度どちらかのメソッドを実行した暗号化・復号用オブジェクトは、もう一方のメソッドを実行することができません。つまり、暗号化・復号用オブジェクトは作成方法は共通していますが、どちらか一方の用途でしか使用できないオブジェクトとなっています。
ここまでを踏まえた上で、以下のようにencrypt_process()
関数を定義しましょう。
追加【7行目~13行目】
import ucryptolib
key = "abcdefghigklmnop" # 共通鍵(16バイト)
init_vector = "1234567891234567" # 初期ベクトル(16バイト)
def encrypt_process(): # ターミナルから入力されたメッセージを暗号化するプロセス
aes_en = ucryptolib.aes(key, 2, init_vector) # 暗号化用オブジェクトの作成
msg = input("Input your message >>> ") # メッセージの入力
if len(msg) > 16: # 16字を超えた場合はプロセスを終了する
print("Please enter the message within 16 characters.")
return
padding_msg = "{:*>16}".format(msg) # 16字(16バイト)にするためのパディング
encrypted_msg = aes_en.encrypt(padding_msg) # 暗号化
network_process(encrypted_msg) # メッセージの送信
暗号化するメッセージも、共通鍵や初期ベクトルと同じ16バイトに合わせなければなりません。そこで、16字に満たない場合は「*
」で16字になるまで埋めておきます(13行目)。この処理をパディングといいます。
そして、暗号化したメッセージは次に定義するnetwork_process
に渡します(15行目)。
■ ネットワークのプロセスの作成
ネットワークのプロセスは、いたってシンプルです。暗号化されたメッセージの内容が確認できるようにprint
文で出力して、受信側のプロセスに渡します。
追加【16行目~18行目】
def network_process(msg): # メッセージを受信側へ届けるプロセス
print("Now sending ... {}".format(msg)) # 暗号化されたメッセージを表示
decrypt_process(msg) # 受信側のプロセスへメッセージを渡す
■ 受信側のプロセスの作成
最後に受信側のプロセスを作成します。受け取ったメッセージを復号用オブジェクトのdecrypt()
メソッドで復号し、元のメッセージを表示しましょう。
追加【20行目~25行目】
def decrypt_process(msg): # 受け取ったメッセージを復号するプロセス
aes_de = ucryptolib.aes(key, 2, init_vector) # 復号用オブジェクトの作成
decrypted_msg = aes_de.decrypt(msg) # 複合
decoded_msg = decrypted_msg.decode("utf-8") # バイト列から文字列に変換
original_msg = decoded_msg.strip("*") # パディングの削除
print("Now received ... {}".format(original_msg)) # メッセージの表示
decrypt()
メソッドで復号したメッセージは、バイト列になっています。そのため、decode()
メソッドで文字列に変換し、さらにパディングで追加した「*
」をstrip()
メソッドで削除します(23・24行目)。
■ プログラムの実行
完成した以下のプログラムを実行して、ターミナルからencrypt_process()
関数を呼び出してみましょう。適当なメッセージを入力すると、残りのプロセスが実行されて、結果が表示されます。
【 サンプルコード 2-3-1 】
import ucryptolib
key = "abcdefghigklmnop" # 共通鍵(16バイト)
init_vector = "1234567891234567" # 初期ベクトル(16バイト)
def encrypt_process(): # ターミナルから入力されたメッセージを暗号化するプロセス
aes_en = ucryptolib.aes(key, 2, init_vector) # 暗号化用オブジェクトの作成
msg = input("Input your message >>> ") # メッセージの入力
if len(msg) > 16: # 16字を超えた場合はプロセスを終了する
print("Please enter the message within 16 characters.")
return
padding_msg = "{:*>16}".format(msg) # 16字(16バイト)にするためのパディング
encrypted_msg = aes_en.encrypt(padding_msg) # 暗号化
network_process(encrypted_msg) # メッセージの送信
def network_process(msg): # メッセージを受信側へ届けるプロセス
print("Now sending ... {}".format(msg)) # 暗号化されたメッセージを表示
decrypt_process(msg) # 受信側のプロセスへメッセージを渡す
def decrypt_process(msg): # 受け取ったメッセージを復号するプロセス
aes_de = ucryptolib.aes(key, 2, init_vector) # 復号用オブジェクトの作成
decrypted_msg = aes_de.decrypt(msg) # 複合
decoded_msg = decrypted_msg.decode("utf-8") # バイト列から文字列に変換
original_msg = decoded_msg.strip("*") # パディングの削除
print("Now received ... {}".format(original_msg)) # メッセージの表示
(プログラムの実行例)
>>> encrypt_process() Input your message >>> hello Now sending ... b'\xbe\x0e*\x91l\xfd\\1\xee\x14\xea-AO\x05\xa3' Now received ... hello
上の例では、「hello
」というメッセージを送っています。これをそのままバイト列に変換すると、「b'\x68\x65\x6c\x6c\x6f'
」となります。ターミナルの表示と比較すると、メッセージが暗号化されて解読できなくなっていることが分かります。
チャプター3
データを復号できない形式へ変換するハッシュ化
ここで紹介する「ハッシュ化」は、暗号化と同じくデータを解読できない形に変換する技術です。暗号化との大きな違いは、ハッシュ化されたデータは複合ができないという点です。
元に戻せないということは、メッセージなど相手が確認することを前提としたデータの保護にハッシュ化を利用することはまずありません。では一体どういった場合にハッシュ化を使うのでしょうか。
3. 1 ハッシュ化を使うケース
ハッシュ化はデータベースにパスワードを保管するときに使われることがあります。
パスワードは、データベース上に保管されている情報の中でも、最も守られなければならない情報のひとつです。データベースからパスワードが流出してしまうと、会員になりすました第三者にサービスを悪用されてしまうでしょう。
一方で、パスワードがハッシュ化されていれば、元のパスワードを特定することができないため、万が一、流出した場合でも被害を最小限に抑えることができます。
3. 2 MicroPythonでのハッシュ化の実践
MicroPythonでは、uhashlib
モジュールでハッシュ化の機能が提供されています。このモジュールでは、次の3つのハッシュ化のアルゴリズムがサポートされています。
- SHA256
- SHA1
- MD5
それぞれのアルゴリズムの詳細な説明を行うと難しくなるので、ここでは「MD5 < SHA1 < SHA256」の順に、セキュリティ能力が高いということを覚えておきましょう。
それでは、前のテーマ.10-3で作成した認証システムと同じケースを想定して、データベースに保管するパスワードをハッシュ化してみましょう。ハッシュ化のアルゴリズムには「SHA256」を採用します。
■ パスワードをハッシュ化して保管したデータベースの準備
プログラムを簡単にするために、btree
モジュールの代わりに、辞書型をデータベースとして使います。ユーザーのIDをキーにして、uhashlib
モジュールのsha256()
関数でハッシュ化し、さらにdigest()
関数でバイト列化したパスワードを値に設定しましょう。
import uhashlib
db = { # 辞書で代用した仮想のデータベース
"id1": uhashlib.sha256("123456").digest(), # パスワードをハッシュ化&バイト列化
"id2": uhashlib.sha256("654321").digest(),
"id3": uhashlib.sha256("223344").digest(),}
■ ログイン関数の作成
ユーザーが入力したIDとパスワードでログイン認証を行う関数を定義します。入力されたID情報からデータベース上に保管されているパスワードを取得し、入力されたパスワードをハッシュ化とバイト列化して比較することで認証を行います。
追加【9行目~19行目】
import uhashlib
db = {
"id1": uhashlib.sha256("123456").digest(),
"id2": uhashlib.sha256("654321").digest(),
"id3": uhashlib.sha256("223344").digest(),
}
def login(_id, _pass): # 入力したIDとパスワードでログイン認証を行う関数
try: # データベース上にIDがあるかどうかの確認
db_pass = db[_id]
except KeyError: # IDが存在しなかった場合
print("The id does'nt exist.")
return
# 入力されたパスワードをハッシュ化して、データベース上のパスワードと照合する
if db_pass == uhashlib.sha256(_pass).digest(): # 認証成功の場合
print("Login.")
else: # 認証失敗の場合
print("The password is invalid.")
■ データベースからの情報漏洩を想定した関数の作成
また、情報漏洩が起きてしまったケースを想定して、データベースに保管されている情報の一覧が表示される関数を作成しておきましょう。これでプログラムの完成です。
【 サンプルコード 3-2-1 】
追加【20行目~23行目】
import uhashlib
db = {
"id1": uhashlib.sha256("123456").digest(),
"id2": uhashlib.sha256("654321").digest(),
"id3": uhashlib.sha256("223344").digest(),
}
def login(_id, _pass):
try:
db_pass = db[_id]
except KeyError:
print("The id does'nt exist.")
return
if db_pass == uhashlib.sha256(_pass).digest():
print("Login.")
else:
print("The password is invalid.")
def leak(): # データベースの情報漏洩の発生を仮定した関数
print(db) # データベース表の情報一覧を表示
■ プログラムの実行
完成したプログラムを実行します。まずは、login()
関数を呼び出して、正しいIDとパスワードの組み合わせと、誤った組み合わせを入力した場合の結果を確認してみましょう。
(プログラムの実行例)
>>> login("id1", "1234") Your password is incorrect. >>> login("id4", "123456") Your id does'nt exist. >>> login("id1", "123456") Login.
ハッシュ化されたパスワードどうしを比較しているため、問題なくログイン認証を行えています。
今度は、leak()
関数を実行して、データベースに保管されているパスワードを確認してみましょう。
(プログラムの実行例)
>>> leak() {'id3': b'\x19\xe5\x8e\xfc\x7fq\xd3\xec\x0b\xd4mE\x1e\x84gO\x07,\xcct\xc3\x12\x8fO\x01~i\x81\xd4\xe9%C', 'id1': b'\x8d\x96\x9e\xefn\xca\xd3\xc2\x9a:b\x92\x80\xe6\x86\xcf\x0c?]Z\x86\xaf\xf3\xca\x12\x02\x0c\x92:\xdcl\x92', 'id2': b'H\x1fl\xc0Q\x11C\xcc\xdd~-\x1b\x1b\x94\xfa\xf0\xa7\x00\xa8\xb4\x9c\xd19"\xa7\x0bZ\xe2\x8a\xca\xa8\xc5'}
バイト列になっているため、少し分かりにくいのですが、明らかに元の単純な6桁の数字のパスワードよりも複雑なデータになっていることが分かります。仮にこのデータが覗かれてしまったとしても、元のパスワードが推測されてしまうのは現実的ではありません。
チャプター4
ゲートの組立て
レッスンの後半からは、ここまでで学習した「暗号化/復号」と「ハッシュ化」の技術を応用して、セキュリティ能力の高い認証システムを搭載したゲートを制作します。まずは、ブロックでゲートの形を組み立てましょう。
4. 1 組み立てに必要なパーツ
【 パーツ一覧 】
- Studuino:bit×1
- ロボット拡張ユニット×1
- 電池ボックス×1
- サーボモーター×1
- ブロック基本四角(グレー)×2
- ブロック基本四角(赤)×4
- ブロックハーフA(グレー)×3
- ブロックハーフB(黒)×1
- ブロックハーフC(白)×12
- ブロックハーフD(白)×8
- ステー×7
- ギヤ小×1
- ラック×1
【 アーテックブロックの形状 】
4. 2 組立説明書
以下のリンク先から組立説明書を確認しましょう。
チャプター5
認証システムを搭載したゲートの制作
インターネットは誰もが気軽にアクセスして利用できるという高い利便性がある一方で、悪意をもった利用者がウィルス攻撃やフィッシングなどを行い、流出した情報を使って他人へのなりすましを行うなどの危険性も多く潜んでいます。
このような危険を回避する方法として、メールやSNS、ブログ、ネットゲーム、ネットショッピングなのサービス提供者は、利用者へ個別のIDとパスワードを付与したアカウントを発行しています。
最近では、電話回線を利用したショートメッセージによるワンタイムパスワードの発行を組み合わせた2段階認証や、個人の指紋や顔の形を利用した生体認証など、より安全性の高い認証システムが積極的に使われるようになってきています。
もちろんセキュリティの問題は、インターネット上だけの話ではありません。例えば、オフィスやマンションでは、部外者が無断で侵入できないように出入口に暗証番号やカードで開くドアを設置しています。
そこで今回は、IDとパスワードによる認証で入場を制限するゲートシステムを作成します。例として、このゲートを学校の教室や校門に設置することを考えて、各生徒には生徒番号(1~999)と4桁の数字からなるパスワードをアカウントとして配布します。
ゲートシステムは、ここまでに学習した暗号化と復号の技術(ucryptolib
モジュール)とハッシュ化の技術(uhashlib
モジュール)、それから前回のレッスンで学習したデータベースの技術(btree
モジュール)を使い、以下の構成で構築します。
【 ゲートシステムの構成 】
そして、上のシステムを構築するために、プログラムでは以下の関数を作成します。
【 作成する関数の一覧 】
関数名 | 処理内容 |
---|---|
register_students() | データベースへアカウント情報を登録する関数 |
show_db() | データベース上のアカウント情報の一覧を表示する関数 |
gate_process() | ゲートのプロセスを行う関数 |
auth_process() | 認証のプロセスを行う関数 |
main() | 他の関数を実行するメイン関数 |
それでは、次の手順に沿って5つの関数を作成し、プログラムを完成させましょう。
5. 1 プログラムの作成
作成するプログラムは、少し複雑な仕組みで動作するため、途中で実行結果を確認しながらコーディングを進めていきましょう。
■ 生徒のアカウント情報を登録する処理(register_students関数)
この関数では、引数に渡された生徒のアカウント情報をデータベースに登録する処理を行います。生徒のアカウント情報は以下の3つで構成され、データベースへは、生徒番号をキーとし、生徒の名前と4桁の数字で表したパスワードを値として登録します。
【 生徒のアカウント情報 】
student_number
: 生徒番号(キー)name
: 生徒の名前(値)password
: 4桁の数字で表したパスワード(値)
そして、この関数へは複数のアカウント情報(辞書)をまとめたリストを渡すようにします。
【 渡すリストの例 】
students_list = [ # 登録する生徒のアカウント情報 {"student_number": 1, "name": "Tanaka", "password": "2312"}, {"student_number": 2, "name": "Ogura", "password": "4512"}, {"student_number": 3, "name": "Hatanaka", "password": "7543"}, {"student_number": 4 , "name": "Morita", "password": "0324"}, ] register_students(students_list) # 引数に渡して登録を行う
そして、このリストから順番にアカウント情報を取り出して、データベースへの登録を行います。このときにパスワードはSHA256
でハッシュ化して記録します。
それではまず、データベースを開く処理から書きましょう。データベースとして使用するファイル名は自由に決めてください。
import btree
FILE_NAME = "school_db" # データベース作成用に使用するファイル名
def register_students(_list):
try:
file = open(FILE_NAME, 'r+b') # データベース用のファイルを開く(書き込みも可能なモード)
except OSError: # ファイルが存在しなかった場合は「OSError」が発生
file = open(FILE_NAME, 'w+b') # ファイルがない場合は新たに作成する(読み込みも可能なモード)
db = btree.open(file) # ファイルからデータベースを作成
次に、引数に渡されたリストから順番にアカウント情報を取り出して、バイト列化とハッシュ化を行います。名前とパスワードはひとつの値として記録するため、2つのデータの間に「,
」を加えて結合します。
データベースへすべてのアカウント情報が一時的に記憶できたら、flush()
メソッド実行して、ファイルへの書き込みを行います。最後にデータベースとファイルを閉じるのを忘れないようにしましょう。
追加【2行目、13行目~21行目】
import btree
import uhashlib # ハッシュ化のためのモジュール
FILE_NAME = "school_db"
def register_students(_list):
try:
file = open(FILE_NAME, 'r+b')
except OSError:
file = open(FILE_NAME, 'w+b')
db = btree.open(file)
for data in _list:
key = data["student_number"].to_bytes(1, "big") # 整数値をビッグエンディアンでバイト列化
name = (data["name"] + ",").encode("utf-8") # 「,」を末尾に追加してパスワードと結合し、値として登録する
password = uhashlib.sha256(data["password"]).digest() # パスワードのみハッシュ化とバイト列化する
val = name + password # 名前とパスワードを結合したものを値として記録する
db[key] = val # 一時的に記憶
db.flush() # ファイルへ書き込む
db.close() # データベースを閉じる
file.close() # データベースで利用しているファイルを閉じる
これで、データベースへ登録する関数ができたので、テスト用のアカウント情報を用意して実行してみましょう。
students_list = [ # データベースへ登録するアカウント情報
{"student_number": 1, "name": "Tanaka", "password": "2312"},
{"student_number": 2, "name": "Ogura", "password": "4512"},
{"student_number": 3, "name": "Hatanaka", "password": "7543"},
{"student_number": 4 , "name": "Morita", "password": "0324"},
]
register_students(students_list) # データベースに登録
エラーが発生しなければ、無事にデータベースに登録できていますが、登録情報を直接確認できていないので少し不安です。そこで、データベース上の情報の一覧を表示する関数を作成して確かめてみましょう。
■ データベース上の情報の一覧を表示する処理(show_db関数)
show_db()
関数をregister_students()
関数の下に定義します。関数の始めに、データベースを開く処理を書きましょう。この関数では、データベースへの書き込みは発生しないため、ファイルは読み込み専用のバイナリモード("rb"
)で開きます。
追加【24行目~30行目】
def show_db():
try:
file = open(FILE_NAME, "rb") # データベース用のファイルを開く(読み込み専用モード)
except OSError: # 失敗した場合
print("{} does'nt exist.".format(FILE_NAME))
return # ファイルが存在しなかったので、ここで処理を終える
db = btree.open(file)
開いたデータベースの情報をターミナルに表示します。データベースも辞書と同じくitems()
メソッドを持っているため、キーと値を順番に取り出すときは、「for key, val in db.items():
」のように書くことができました。また、値は名前とパスワードを「,
」で結合したものにしていたため、文字列のsplit()
メソッドで分割します。ただし、分割文字の「,
」を「b","
」とバイト列で指定している点に注意してください(33行目)。
追加【31行目~38行目】
def show_db():
try:
file = open(FILE_NAME, "rb")
except OSError:
print("{} does'nt exist.".format(FILE_NAME))
return
db = btree.open(file)
for key, val in db.items(): # btreeオブジェクトは辞書と同様にitems()メソッドを持つ
num = int.from_bytes(key.decode(), "big") # ビッグエンディアンのバイト列を整数値に戻す
val = val.split(b",") # 「,」で結合していた名前とパスワードをリストに分割
name = val[0].decode("utf-8") # バイト列から文字列に戻す
password = val[1] # パスワードはハッシュ化されているので元には戻せない
print("{}, {}, {}".format(num, name, password))
db.close() # データベースとファイルを閉じるのを忘れないように注意
file.close()
では、テスト用のアカウント情報を登録していた処理をコメント化して、その下にshow_db()
関数を実行するコードを追加して、ここまでのプログラムを実行してみましょう。
変更・追加【40行目~49行目】
""" コメント化
students_list = [
{"student_number": 1, "name": "Tanaka", "password": "2312"},
{"student_number": 2, "name": "Ogura", "password": "4512"},
{"student_number": 3, "name": "Hatanaka", "password": "7543"},
{"student_number": 4 , "name": "Morita", "password": "0324"},
]
register_students(students_list)
"""
show_db() # データベース上の情報の一覧を表示する
(実行結果)
1, Tanaka, b"\x08\xdd\x19\xeb\xe32\xae\xb6{\xca0X\x9eT\xe6'#)I\xc77=>5?\x94\xc2\x1fi\xa9\xd9\xc5" 2, Ogura, b'\x035\x81\xb0\x97\x04w\xaf\x91o\x08\xad\x93\x1cR\x1b\x97[U\xf86\x86\x04\xaeX\xa57\xb3\x87\xe7\x92\xe1' 3, Hatanaka, b'C\xd5\x99hR\xcc\x0c{\xea\x16\x14\x8b\xb2r\x1e\xb3\x17\xcd\x9e\x17&\x15\x11\x08\x96\xd0\xa6\xdbd\xc4e\x0c' 4, Morita, b'\x87R\xf2N\xc0\xa8\xacP\xefs/\xba\xa2o-\xf1\xce\xa3.G{\x8dJ\xd4\x16\x07H\x15^\xd20T'
上と同じような実行結果が得られれば成功です。パスワードは複雑にハッシュ化されているため、元の4桁の数字を推測することは困難でしょう。
■ ゲートで入力されたアカウント情報を認証のプロセスへ送る処理(gate_process関数)
テスト用のアカウント情報が登録できたので、ここからはそれを使って認証を行い、ゲートを開閉する処理を書いていきます。
まずは、ゲート側のプロセスでアカウント情報の入力を受け付けて、その情報を暗号化して送るまでのところを作りましょう。アカウント情報はキューを介してゲート側のプロセスから認証側のプロセスへ渡します。
追加【3行目、6~8行目、42行目~50行目】
※ 暗号化・復号用の共通鍵と初期ベクトルは16字の英数字であれば、何でも構いません。
import btree
import uhashlib
import ucryptolib # 暗号化と復号のためのモジュール
FILE_NAME = "school_db"
crypto_key = "python1234python" # 暗号化と復号用の共通鍵(16字)
init_vector = "0123456789012345" # 初期ベクトル(16バイト)
que_gate_to_auth = [] # ゲート側のプロセスから認証のプロセスへ情報を渡すためのキュー
db.close()
file.close()
def gate_process():
aesobj = ucryptolib.aes(crypto_key, 2, init_vector) # 暗号化のためのオブジェクトの作成
while True:
num = input("Input your student number. >>>") # 生徒番号の入力
password = input("Input your password. >>>") # パスワードの入力
num = aesobj.encrypt("{:*>16}".format(num)) # 16字(byte)に満たない部分を「*」で埋めて暗号化
password = aesobj.encrypt("{:*>16}".format(password)) # 16字(byte)に満たない部分を「*」で埋めて暗号化
que_gate_to_auth.append((num, password)) # 暗号化された入力データ(生徒番号、パスワード)をキューに追加
■ アカウント情報を受け取って復号する処理(auth_process関数)
次は、認証のプロセス側で暗号化されたアカウント情報を受け取って、復号する処理を作成します。認証を行うアカウント情報はキュー(que_gate_to_auth
)に追加されていくため、一定時間おきにチェックするコードを書き、情報があった場合は取り出して復号します。
そして、送信情報は16字(byte)に満たない場合、暗号化する前に「*
」で埋めていたため、文字列のstrip()
メソッドでこれを削除します。また、生徒番号はバイト列から整数値に戻します。
追加【4行目、54行目~66行目】
import btree
import uhashlib
import ucryptolib
import time # 時間制御のためのモジュール
def auth_process():
aesobj = ucryptolib.aes(crypto_key, 2, init_vector) # 復号用のオブジェクト
while True:
time.sleep_ms(100) # 100ミリ秒おきにゲート側からの入力情報があるかどうかをチェック
if len(que_gate_to_auth):
data = que_gate_to_auth.pop(0) # ゲート側からの入力情報の受け取り
num = aesobj.decrypt(data[0]) # 復号する
num = num.strip(b"*") # 「*」を削除する
num = int(num) # 整数値に変換
password = aesobj.decrypt(data[1])
password = password.strip(b"*")
print("Now received", num, password) # 確認のためターミナルに表示
では、ここまでに追加した処理の動作を確認しましょう。auth_process()
関数をスレッドを立ち上げて実行するコードを追加します。
変更・追加【5行目、78行目~80行目】
import btree
import uhashlib
import ucryptolib
import time
import _thread # スレッド用のモジュール
""" コメント化
students_list = [
{"student_number": 1, "name": "Tanaka", "password": "2312"},
{"student_number": 2, "name": "Ogura", "password": "4512"},
{"student_number": 3, "name": "Hatanaka", "password": "7543"},
{"student_number": 4 , "name": "Morita", "password": "0324"},
]
register_students(students_list)
show_db() # この関数の実行もコメント化
"""
_thread.start_new_thread(auth_process, ())
このプログラムを実行し、ターミナルからgate_process()
関数を呼び出して、生徒番号とパスワードを入力します。直後にauth_process()
関数から情報を受け取ったことを示すメッセージが表示されれば成功です。
>>> gate_process() Input your student number. >>>1 Input your password. >>>1234 Input your student number. >>>Now received 1 b'1234'
■ アカウント情報の認証を行う処理(auth_process関数)
これで認証に必要なアカウント情報の受け渡しができるようになったので、データベース上の情報と照合して、認証を行う処理を作成していきます。
まずは、auth_process()
関数の始めにデータベースを開くためのコードを追加しましょう。また、74行目のprint
文は不要になったので、コメント化するか削除しておきましょう。
【58行目~63行目、74行目】
def auth_process():
aesobj = ucryptolib.aes(crypto_key, 1)
try:
file = open(FILE_NAME, 'rb') # 読み込み専用モードで開く
except OSError:
print("{} does'nt exist.".format(FILE_NAME))
return # ファイルが存在しなかった場合はここで処理を終える
db = btree.open(file)
while True:
time.sleep_ms(100)
if len(que_gate_to_auth):
data = que_gate_to_auth.pop(0)
num = aesobj.decrypt(data[0])
num = num.strip(b"*")
num = int(num)
password = aesobj.decrypt(data[1])
password = password.strip(b"*")
# print("Now received", num, password) # 不要になったのでコメント化
受け取ったアカウント情報から生徒番号を使って、データベース上で検索を掛けます。もし、生徒番号が存在しなかった場合は、ゲート側のプロセスに認証に失敗したことを伝えます。このときの情報の受け渡しにもキューを使いますので、新しいキューを用意しましょう。また、送る情報は(認証の成否を表すbool値, メッセージの文字列)
のタプルとし、受け取ったゲート側のプロセスがTrue
またはFalse
で成否を判断できるようにしておきましょう。
追加【11行目、78行目~82行目】
FILE_NAME = 'school_db'
crypto_key = "python1234python"
init_vector = "0123456789012345"
que_gate_to_auth = []
que_auth_to_gate = [] # 認証プロセスからゲートプロセスへ情報を受け渡すためのキュー
while True:
time.sleep_ms(100)
if len(que_gate_to_auth):
data = que_gate_to_auth.pop(0)
num = aesobj.decrypt(data[0])
num = num.strip(b"*")
num = int(num)
password = aesobj.decrypt(data[1])
password = password.strip(b"*")
# print("Now received", num, password)
try: # データべ―ス上で生徒番号を検索して値を取得
db_val = db[num.to_bytes(1, "big")] # データベースへの登録時と同様にビッグエンディアンでバイト列化する
except KeyError: # データベース上に対象の生徒番号が存在しなかった場合
que_auth_to_gate.append((False, "Your number does'nt exist.")) # 生徒番号が存在しなかったことを伝えるメッセージをキューを通してゲート側に渡す
continue # 次のループに移る
生徒番号が検索にヒットした場合は、データベースから値を読み込んで、結合していた名前とパスワードを分割して取り出します。この手順はshow_db()
関数と同様です。送られてきたパスワードは、データベースのパスワードと照合するために、ハッシュ化して比較します。2つが一致した場合は、認証に成功したものとして、True
と生徒の名前を含めたメッセージをゲート側のプロセスに送ります。不一致の場合は、False
とパスワードが正しくなかったことを伝えるメッセージを送ります。
追加【83行目~89行目】
while True:
time.sleep_ms(100)
if len(que_gate_to_auth):
data = que_gate_to_auth.pop(0)
num = aesobj.decrypt(data[0])
num = num.strip(b"*")
num = int(num)
password = aesobj.decrypt(data[1])
password = password.strip(b"*")
# print("Now received", num, password)
try:
db_val = db[num.to_bytes(1, "big")]
except KeyError:
que_auth_to_gate.append((False, "Your number does'nt exist."))
continue
db_val = db_val.split(b",") # 「,」接続していた名前とパスワードを分割
db_name = db_val[0].decode("utf-8") # 名前はutf-8でデコード
db_pass = db_val[1] # パスワードはハッシュ化されたバイト列をそのまま利用
if uhashlib.sha256(password).digest() == db_pass: # 送られてきたパスワードをハッシュ化して、データベースのパスワードと照合する
que_auth_to_gate.append((True, "Hi! " + db_name)) # 一致した場合にゲート側へ渡すデータ
else:
que_auth_to_gate.append((False, "Your password is incorrect.")) # 一致しなかった場合にゲート側へ渡すデータ
■ 認証結果を受けてゲートを開閉する処理(gate_process関数)
続けて、ゲート側のプロセスで認証結果を受け取って、ゲートを開閉する処理を作成していきます。
ゲート側では、ゲートを開閉するためのサーボモーターや、認証結果を知らせるためのLEDディスプレイやブザーを使用します。プログラムの先頭で必要なオブジェクトやクラスをインポートして、インスタンスを作成しましょう。
追加【6・7行目、14行目】
import btree
import uhashlib
import ucryptolib
import time
import _thread
from pystubit.board import display, buzzer, Image # 新たにインポート
from pyatcrobo2.parts import Servomotor # 新たにインポート
FILE_NAME = "school_db"
crypto_key = "python1234python"
init_vector = "0123456789012345"
que_gate_to_auth = []
que_auth_to_gate = []
servo = Servomotor("P16") # インスタンスの作成
ターミナルから入力されたアカウント情報を認証プロセス側に送ったあとは、認証プロセス側から認証結果が返って来るまで(キューにデータが格納されるまで)待機します。
追加【60行目~62行目】
def gate_process():
aesobj = ucryptolib.aes(crypto_key, 1)
while True:
num = input("Input your student number. >>>")
password = input("Input your password. >>>")
num = aesobj.encrypt("{:*>16}".format(num))
password = aesobj.encrypt("{:*>16}".format(password))
que_gate_to_auth.append((num, password))
while not len(que_auth_to_gate): # 認証プロセス側から結果が返ってくるまで待つ
time.sleep_ms(100)
pass
認証結果を受け取ったら、内容を確認します。メッセージを表示して、LEDディスプレイへとブザー音で成功か失敗かを知らせましょう。また、成功の場合はサーボモーターを動かして、ゲートを5秒間開きます。
追加【63行目~80行目】
def gate_process():
aesobj = ucryptolib.aes(crypto_key, 2, init_vector)
while True:
num = input("Input your student number. >>>")
password = input("Input your password. >>>")
num = aesobj.encrypt("{:*>16}".format(num))
password = aesobj.encrypt("{:*>16}".format(password))
que_gate_to_auth.append((num, password))
while not len(que_auth_to_gate):
time.sleep_ms(100)
pass
result = que_auth_to_gate.pop(0) # 認証結果を取得
print(result[1]) # 認証プロセス側から送られたメッセージを表示
if result[0]: # 認証に成功した場合
display.show(Image.YES, delay=0, color=(0, 31, 0))
buzzer.on("72", duration=200)
time.sleep_ms(100)
buzzer.on("68", duration=600)
servo.set_angle(75) # 5秒間だけドアを開く
time.sleep_ms(5000)
servo.set_angle(180)
time.sleep_ms(1000)
display.clear()
else: # 認証に失敗した場合
display.show(Image.NO, delay=0)
buzzer.on("48", duration=200)
time.sleep_ms(100)
buzzer.on("48", duration=600)
display.clear()
■ main関数に処理をまとめる
これで必要な機能が揃いました。最後にコメント化していたところも含めて、main()
関数にまとめて実行できるようにしましょう。
追加【117行目~128行目】
if uhashlib.sha256(password).digest() == db_pass:
que_auth_to_gate.append((True, "Hi! " + db_name))
else:
que_auth_to_gate.append((False, "Your password is incorrect."))
def main():
students_list = [ # コメント化の解除
{"student_number": 1, "name": "Tanaka", "password": "2312"},
{"student_number": 2, "name": "Ogura", "password": "4512"},
{"student_number": 3, "name": "Hatanaka", "password": "7543"},
{"student_number": 4 , "name": "Morita", "password": "0324"},
]
# show_db()関数の実行は必要ないので削除
register_students(students_list) # データベースへの登録を実行
servo.set_angle(180) # 始めはゲートのドアを閉じた状態にしておく
_thread.start_new_thread(auth_process, ()) # スレッドを立ち上げて認証プロセスを実行
gate_process() # ゲート側のプロセスを実行
5. 2 プログラムの動作確認
完成したプログラムを実行して、正しいアカウント情報を入力した場合と誤ったアカウント情報を入力した場合の両方で動作を確かめましょう。
【 入力例 】
>>> main() Input your student number. >>>1 Input your password. >>>2312 Hi! Tanaka Input your student number. >>>2 Input your password. >>>4513 Your password is incorrect. Input your student number. >>>5 Input your password. >>>2233 Your number does'nt exist.
もし、問題が改善できない場合は、以下のサンプルコードと見比べて誤りがないか1行ずつ確かめましょう。
【 サンプルコード 4-3-1 】
import btree
import uhashlib
import ucryptolib
import time
import _thread
from pystubit.board import display, buzzer, Image
from pyatcrobo2.parts import Servomotor
FILE_NAME = "school_db"
crypto_key = "python1234python"
init_vector = "0123456789012345"
que_gate_to_auth = []
que_auth_to_gate = []
servo = Servomotor("P16")
def register_students(_list):
try:
file = open(FILE_NAME, 'r+b')
except OSError:
file = open(FILE_NAME, 'w+b')
db = btree.open(file)
for data in _list:
key = data["student_number"].to_bytes(1, "big")
name = (data["name"] + ",").encode("utf-8")
password = uhashlib.sha256(data["password"]).digest()
val = name + password
db[key] = val
db.flush()
db.close()
file.close()
def show_db():
try:
file = open(FILE_NAME, "rb")
except OSError:
print("{} does'nt exist.".format(FILE_NAME))
return
db = btree.open(file)
for key, val in db.items():
num = int.from_bytes(key.decode(), "big")
val = val.split(b",")
name = val[0].decode("utf-8")
password = val[1]
print("{}, {}, {}".format(num, name, password))
db.close()
file.close()
def gate_process():
aesobj = ucryptolib.aes(crypto_key, 2, init_vector)
while True:
num = input("Input your student number. >>>")
password = input("Input your password. >>>")
num = aesobj.encrypt("{:*>16}".format(num))
password = aesobj.encrypt("{:*>16}".format(password))
que_gate_to_auth.append((num, password))
while not len(que_auth_to_gate):
time.sleep_ms(100)
pass
result = que_auth_to_gate.pop(0)
print(result[1])
if result[0]:
display.show(Image.YES, delay=0, color=(0, 31, 0))
buzzer.on("72", duration=200)
time.sleep_ms(100)
buzzer.on("68", duration=600)
servo.set_angle(75)
time.sleep_ms(5000)
servo.set_angle(180)
time.sleep_ms(1000)
display.clear()
else:
display.show(Image.NO, delay=0)
buzzer.on("48", duration=200)
time.sleep_ms(100)
buzzer.on("48", duration=600)
display.clear()
def auth_process():
aesobj = ucryptolib.aes(crypto_key, 2, init_vector)
try:
file = open(FILE_NAME, 'rb')
except OSError:
print("{} does'nt exist.".format(FILE_NAME))
return
db = btree.open(file)
while True:
time.sleep_ms(100)
if len(que_gate_to_auth):
data = que_gate_to_auth.pop(0)
num = aesobj.decrypt(data[0])
num = num.strip(b"*")
num = int(num)
password = aesobj.decrypt(data[1])
password = password.strip(b"*")
# print("Now received", num, password)
try:
db_val = db[num.to_bytes(1, "big")]
except KeyError:
que_auth_to_gate.append((False, "Your number does'nt exist."))
continue
db_val = db_val.split(b",")
db_name = db_val[0].decode("utf-8")
db_pass = db_val[1]
if uhashlib.sha256(password).digest() == db_pass:
que_auth_to_gate.append((True, "Hi! " + db_name))
else:
que_auth_to_gate.append((False, "Your password is incorrect."))
def main():
students_list = [
{"student_number": 1, "name": "Tanaka", "password": "2312"},
{"student_number": 2, "name": "Ogura", "password": "4512"},
{"student_number": 3, "name": "Hatanaka", "password": "7543"},
{"student_number": 4 , "name": "Morita", "password": "0324"},
]
register_students(students_list)
servo.set_angle(180)
_thread.start_new_thread(auth_process, ())
gate_process()
チャプター6
課題:正規表現を使って入力されたアカウント情報を事前にチェックする
前のレッスンでは、正規表現とマッチングについて学習し、簡単な認証システムにおいて、ターミナルから入力されたメールアドレスやパスワードの書式に誤りがないかをチェックする機能を作成しました。
そこでこの課題では、復習も兼ねて【 サンプルコード 4-3-1 】へ、ユーザーが入力した生徒番号やパスワードの書式に誤りがある場合は再入力を求める機能の追加に取り組みます。
入力する情報 | 書式 |
---|---|
生徒番号 | 1~999までの3桁の番号 |
パスワード | 0~9の数字を組み合わせた4桁の文字列 |
正規表現の書き方やマッチングの方法を忘れたという場合は、先に前回のレッスンを見直しましょう。
6. 1 プログラムの変更手順
正規表現を扱うので、ure
モジュールをインポートします。
追加【6行目】
import btree
import uhashlib
import ucryptolib
import time
import _thread
import ure # 簡易的な正規表現を扱うモジュール
from pystubit.board import display, buzzer, Image
from pyatcrobo2.parts import Servomotor
生徒番号とパスワードのそれぞれの正規表現を定義して、マッチングのための正規表現オブジェクトを作成します。
追加【54行目~57行目】
def gate_process():
aesobj = ucryptolib.aes(crypto_key, 2, init_vector)
pat_student_num = "^[1-9]$|^[1-9]\d$|^[1-9]\d\d$" # 生徒番号(1~999)
pat_pass = "^\d\d\d\d$" # パスワード(4桁の数字)
regex_student_num = ure.compile(pat_student_num) # 正規表現のオブジェクトを作成
regex_pass = ure.compile(pat_pass)
ターミナルから入力された生徒番号とパスワードに対してマッチングを行います。どちらか一方でもマッチングに失敗した場合は、continue
文を実行して再入力を促すようにしましょう。
追加【62行目~69行目】
def gate_process():
aesobj = ucryptolib.aes(crypto_key, 2, init_vector)
pat_student_num = "^[1-9]$|^[1-9]\d$|^[1-9]\d\d$"
pat_pass = "^\d\d\d\d$"
regex_student_num = ure.compile(pat_student_num)
regex_pass = ure.compile(pat_pass)
while True:
num = input("Input your student number. >>>")
password = input("Input your password. >>>")
matchobj_num = regex_student_num.match(num) # 生徒番号のマッチング
matchobj_pass = regex_pass.match(password) # パスワードのマッチング
if not matchobj_num or not matchobj_pass: # どちらか一方でも失敗した場合
if not matchobj_num: # 正しい書式での入力を促すメッセージを表示
print("Please enter a student number from 1 to 999.")
if not matchobj_pass:
print("Enter the password using a 4-digit number.")
continue # 59行目のwhile文の先頭に戻る
num = aesobj.encrypt("{:*>16}".format(num))
password = aesobj.encrypt("{:*>16}".format(password))
que_gate_to_auth.append((num, password))
6. 2 プログラムの動作確認
完成したプログラムを実行して、様々なパターンを入力し、動作を確認しましょう。自分で作成したプログラムがうまく動作しない場合は、以下のサンプルコードを参考にして、もう一度プログラムを見直しましょう。
>>> main() Input your student number. >>>3456 Input your password. >>>23456 Please enter a student number from 1 to 999. Enter the password using a 4-digit number. Input your student number. >>>012 Input your password. >>>234 Please enter a student number from 1 to 999. Enter the password using a 4-digit number. Input your student number. >>>2 Input your password. >>>4512 Hi! Ogura
【 サンプルコード 5-2-1 】
import btree
import uhashlib
import ucryptolib
import time
import _thread
import ure
from pystubit.board import display, buzzer, Image
from pyatcrobo2.parts import Servomotor
FILE_NAME = "school_db"
crypto_key = "python1234python"
init_vector = "0123456789012345"
que_gate_to_auth = []
que_auth_to_gate = []
servo = Servomotor("P16")
def register_students(_list):
try:
file = open(FILE_NAME, 'r+b')
except OSError:
file = open(FILE_NAME, 'w+b')
db = btree.open(file)
for data in _list:
key = data["student_number"].to_bytes(1, "big")
name = (data["name"] + ",").encode("utf-8")
password = uhashlib.sha256(data["password"]).digest()
val = name + password
db[key] = val
db.flush()
db.close()
file.close()
def show_db():
try:
file = open(FILE_NAME, "rb")
except OSError:
print("{} does'nt exist.".format(FILE_NAME))
return
db = btree.open(file)
for key, val in db.items():
num = int.from_bytes(key.decode(), "big")
val = val.split(b",")
name = val[0].decode("utf-8")
password = val[1]
print("{}, {}, {}".format(num, name, password))
db.close()
file.close()
def gate_process():
aesobj = ucryptolib.aes(crypto_key, 2, init_vector)
pat_student_num = "^[1-9]$|^[1-9]\d$|^[1-9]\d\d$"
pat_pass = "^\d\d\d\d$"
regex_student_num = ure.compile(pat_student_num)
regex_pass = ure.compile(pat_pass)
while True:
num = input("Input your student number. >>>")
password = input("Input your password. >>>")
matchobj_num = regex_student_num.match(num)
matchobj_pass = regex_pass.match(password)
if not matchobj_num or not matchobj_pass:
if not matchobj_num:
print("Please enter a student number from 1 to 999.")
if not matchobj_pass:
print("Enter the password using a 4-digit number.")
continue
num = aesobj.encrypt("{:*>16}".format(num))
password = aesobj.encrypt("{:*>16}".format(password))
que_gate_to_auth.append((num, password))
while not len(que_auth_to_gate):
time.sleep_ms(100)
pass
result = que_auth_to_gate.pop(0)
print(result[1])
if result[0]:
display.show(Image.YES, delay=0, color=(0, 31, 0))
buzzer.on("72", duration=200)
time.sleep_ms(100)
buzzer.on("68", duration=600)
servo.set_angle(75)
time.sleep_ms(5000)
servo.set_angle(180)
time.sleep_ms(1000)
display.clear()
else:
display.show(Image.NO, delay=0)
buzzer.on("48", duration=200)
time.sleep_ms(100)
buzzer.on("48", duration=600)
display.clear()
def auth_process():
aesobj = ucryptolib.aes(crypto_key, 2, init_vector)
try:
file = open(FILE_NAME, 'rb')
except OSError:
print("{} does'nt exist.".format(FILE_NAME))
return
db = btree.open(file)
while True:
time.sleep_ms(100)
if len(que_gate_to_auth):
data = que_gate_to_auth.pop(0)
num = aesobj.decrypt(data[0])
num = num.strip(b"*")
num = int(num)
password = aesobj.decrypt(data[1])
password = password.strip(b"*")
# print("Now received", num, password)
try:
db_val = db[num.to_bytes(1, "big")]
except KeyError:
que_auth_to_gate.append((False, "Your number does'nt exist."))
continue
db_val = db_val.split(b",")
db_name = db_val[0].decode("utf-8")
db_pass = db_val[1]
if uhashlib.sha256(password).digest() == db_pass:
que_auth_to_gate.append((True, "Hi! " + db_name))
else:
que_auth_to_gate.append((False, "Your password is incorrect."))
def main():
students_list = [
{"student_number": 1, "name": "Tanaka", "password": "2312"},
{"student_number": 2, "name": "Ogura", "password": "4512"},
{"student_number": 3, "name": "Hatanaka", "password": "7543"},
{"student_number": 4 , "name": "Morita", "password": "0324"},
]
register_students(students_list)
servo.set_angle(180)
_thread.start_new_thread(auth_process, ())
gate_process()
チャプター7
おわりに
7. 1 このレッスンのまとめ
このレッスンでは、ネットワーク上での情報のやり取りを安全に行うための技術として、「データの暗号化/復号」と「データのハッシュ化」について学習しました。
様々な情報が自由に行き交うインターネットの世界では、セキュリティの問題は常に付きまといます。今回紹介した技術以外にも、皆さんが安全にインターネットを利用できるように、セキュリティを専門にするエンジニアの活躍によって、今もなお新たな技術開発が続けられています。
テーマ10を通して、様々なデータ処理の技術を学んできました。これまでの全テーマの中で最も難しかったのではないでしょうか。コンピュータやプログラミング、インターネットの世界はもっと奥が深く、学べば学ぶほど高度な技術によって支えられていることが分かります。
早速、次のテーマ11からはインターネットの世界について少し詳しく紹介していきます。残すところあと2テーマですが、最後まで頑張って学習に取り組みましょう。
7. 2 次のレッスンについて
テーマ11では、Studuino:bitをインターネットに接続して、ネットワーク上にある情報を取得して、Studuino:bitを制御するための方法を学習します。レッスンを進める前に、教室に接続可能なwifi環境があることを先生に確認しておきましょう。