【ステップアップ】「Pythonの実践」簡単速習‼【暗号化/応用⑥】

こんにちはヤク学長です。
データサイエンティスト兼ファーマシストで、アルゴリズムやBI開発を行っています。

本記事の目的は、「pythonの基本操作を知る」ことを目的としています。

https://medical-science-labo.jp/python_advance05/

【本記事のもくじ】

まず、「Python」に真剣に取り組むための概要を解説します。
下記の方法で、簡単に概要を抑えることができます。

  • 1.暗号化

それでは、上から順番に見ていきます。
なお、本上記の方法を順番に抑えれば成果が出ます。

記事の内容は「転載 & 引用OK」問題ありません。

1.暗号化

暗号化(encryption)とは、データを第三者から保護するために、元のデータを別の形式に変換する技術です。暗号化によって、データを保護することができ、不正アクセスや盗聴から守ることができます。

暗号化には、対称鍵暗号方式と公開鍵暗号方式の2つがあります。

対称鍵暗号方式は、暗号化と復号に同じ鍵を使用します。鍵を知らないと、暗号文から元のデータを復号できません。対称鍵暗号方式は、高速な暗号化と復号ができるため、大量のデータを扱う場合に適しています。

一方、公開鍵暗号方式は、暗号化と復号に異なる鍵を使用します。公開鍵は誰でも知っていることができる鍵で、秘密鍵は本人しか知っていない鍵です。公開鍵暗号方式は、秘密鍵が漏洩しても、公開鍵を知っている人以外は暗号文を復号できないため、セキュリティ面で安全です。ただし、暗号化や復号が対称鍵暗号方式に比べて遅いため、大量のデータを扱う場合は処理が遅くなります。

Pythonには、標準ライブラリのcryptographyモジュールを使って暗号化を行うことができます。cryptographyモジュールには、対称鍵暗号方式と公開鍵暗号方式の両方に対応した暗号化関数が用意されています。また、暗号化に加えて、ハッシュ関数や認証機能なども提供されています。

文字コード

文字コード(Character encoding)は、コンピュータにおける文字の表現方法の一つで、文字集合と符号化方式から構成されます。文字集合とは、使用する文字の集合のことであり、符号化方式とは、文字集合に含まれる各文字に対して、コンピュータ内部でどのようなビット列を割り当てるかを定義するルールのことです。

文字コードの代表的なものには、ASCII、Unicode、UTF-8などがあります。ASCIIは7ビットの文字コードで英字や数字、記号などを表現し、Unicodeは世界中の文字を含む16ビットの文字コードです。UTF-8はUnicodeを可変長で表現するための方式で、ASCII文字は1バイト、日本語のひらがなや漢字は3バイトで表現されます。

Pythonでは、文字コード変換に関する機能が豊富に用意されており、文字列オブジェクトにはencode()メソッドとdecode()メソッドがあります。encode()メソッドは、Unicode文字列を指定の文字コードでエンコードしてバイト列に変換します。一方、decode()メソッドは、バイト列を指定の文字コードでデコードしてUnicode文字列に変換します。

以下に、UTF-8でエンコードされた文字列をShift_JISでデコードする例を示します。

utf8_string = 'こんにちは'.encode('utf-8')
sjis_string = utf8_string.decode('shift-jis')
print(sjis_string) # 'こんにちは'

このように、Pythonを使って文字コードを変換することで、異なる文字コードのテキストを相互に変換することができます。

ASCII 符号化方式

ASCII (American Standard Code for Information Interchange) は、最も一般的に使用される文字エンコーディングの一つで、8ビットのバイト単位で文字を表現します。ASCII は、英語のアルファベット、数字、記号、および制御文字を表現するために使用されます。ASCII の最初の7ビットは、0から127の範囲の文字を表し、8ビット目はパリティビットに使用されます。ASCII エンコーディングは、今日でも広く使用されていますが、国際化により、より多くの言語に対応するために、Unicode エンコーディングが普及しています。Unicode は、ASCII と互換性があり、さまざまな言語の文字を表現するために、広範なコードポイントを提供しています。

ASCII には、各文字に割り当てられた固定の数値コードがあります。以下は、いくつかの ASCII 文字とその数値コードの例です。

  • ‘A’: 65
  • ‘B’: 66
  • ‘a’: 97
  • ‘b’: 98
  • ‘0’: 48
  • ‘1’: 49
  • ‘\n’: 10

Python では、文字列を ASCII エンコーディングでエンコードすることができます。以下は、Python で文字列を ASCII エンコーディングでエンコードする例です。

text = "Hello, world!"
ascii_text = text.encode("ascii")
print(ascii_text) # b'Hello, world!'

ここで、encode() メソッドに “ascii” を渡すことにより、文字列が ASCII エンコーディングでエンコードされます。エンコードされたバイト文字列は、プレフィックス b で示されます。

ASCII エンコーディングの場合、英語のアルファベット、数字、および一部の記号は、1バイトで表現されます。しかし、ASCII エンコーディングには、多言語の文字に対応するために8ビット以外のエンコーディングも存在します。

Shift-JIS符号化方式

Shift-JISは、主に日本語を含むマルチバイト文字を扱うための符号化方式です。Shift-JISは、半角英数字や記号は1バイト、ひらがな、カタカナ、漢字などのマルチバイト文字は2バイトで表現されます。

PythonでShift-JISの文字列を扱うには、文字列をencodeメソッドでShift-JISにエンコードし、decodeメソッドでShift-JISからデコードする必要があります。

例えば、「こんにちは、世界」という文字列をShift-JISでエンコードし、そのバイト列を表示するには、次のようにします。

s = "こんにちは、世界"
encoded = s.encode('shift-jis')
print(encoded)

出力:

b'\x82\xb1\x82\xf1\x82\xc9\x82\xbf\x82\xcd\x8f\xad\x8f\xc4'

このバイト列をShift-JISからデコードして元の文字列に戻すには、以下のようにします。

decoded = encoded.decode('shift-jis')
print(decoded)

出力:

こんにちは、世界

また、Shift-JISはCP932とも呼ばれ、Windows環境でよく使用されます。Pythonの文字列にはデフォルトでUTF-8が使われるため、Shift-JISの文字列を扱う場合は、明示的にShift-JISを指定する必要があります。

例えば、Shift-JISのテキストファイルを読み込み、その内容をShift-JISからデコードするには、次のようにします。

with open('file.txt', 'r', encoding='shift-jis') as f:
content = f.read()
decoded = content.encode('shift-jis')
print(decoded)

Shift-JISのテキストファイルに書き込む場合は、以下のようにします。

content = "こんにちは、世界"
encoded = content.encode('shift-jis')
with open('file.txt', 'w', encoding='shift-jis') as f:
f.write(encoded.decode('shift-jis'))

Unicode符号化文字規格

Unicodeは、世界のあらゆる言語に対応した文字集合を定義するための規格です。Unicodeは、世界中で使用される文字を1つの文字集合で扱えるようにすることで、異なる言語間での文字コードの混乱を解消し、国際化されたソフトウェアやウェブサイトの開発を容易にします。

Unicodeは、各文字に対して一意な符号(コードポイント)を割り当てることで、多言語をサポートします。現在、Unicodeには100,000を超える文字が定義されています。Unicodeは、ISO 10646という国際規格として標準化されています。

Pythonの文字列は、デフォルトでUnicodeエンコーディングであるUTF-8でエンコードされます。これにより、Pythonは多言語に対応し、異なる文字エンコーディングによる混乱を回避できます。Unicode文字列を扱うには、文字列の前にuを付ける必要があります。また、文字列中にUnicodeエスケープシーケンスを使用することもできます。

例えば、Unicodeエスケープシーケンスを使用してUnicode文字列を作成するには、次のようにします。

unicode_string = u'\u3053\u3093\u306b\u3061\u306f\uff0c\u4e16\u754c\uff01'
print(unicode_string)

このコードは、「こんにちは、世界!」を表示します。

UTF-8 符号化方式

UTF-8は、Unicodeの一種で、複数のバイトを使って文字を表現する可変長の符号化方式です。UTF-8では、1バイトから4バイトまでの可変長のバイト列でUnicode文字を表現します。

UTF-8では、英数字や記号などのASCII文字は1バイトで表現され、一方で多言語に対応するためにUnicodeの追加文字は複数のバイトで表現されます。UTF-8は、ASCII文字を含む多くのテキストデータに対して効率的にエンコードできるため、ウェブサイトやソフトウェアなどで広く使用されています。

例えば、ASCII文字は1バイトで表現され、日本語の漢字は3バイト、エモジなどの一部の文字は4バイトで表現されます。

Pythonでは、文字列をUTF-8でエンコードする場合、encode()メソッドを使用します。また、UTF-8でエンコードされたバイト列を文字列に変換する場合、decode()メソッドを使用します。

例えば、以下のコードは、「こんにちは、世界」という日本語の文字列をUTF-8でエンコードし、再度デコードする例です。

japanese_text = "こんにちは、世界"
utf8_bytes = japanese_text.encode('utf-8')
decoded_text = utf8_bytes.decode('utf-8')
print(decoded_text)

出力:

こんにちは、世界

バイト列 バイナリ列

バイト列(Bytes)とは、コンピュータにおいて、8ビットの整数値の並びで構成されるデータのことを指します。バイト列は、バイナリ列、オクテット列とも呼ばれます。バイト列は、画像、音声、ビデオ、データファイルなど、あらゆる種類のデータを表現するために使用されます。

Pythonにおいて、バイト列はbytes型として表現されます。bytes型のオブジェクトはイミュータブル(変更不可能)であり、一度作成されると内容を変更することはできません。

以下は、Pythonでバイト列を表現する例です。

# バイト列を作成する
b = b'hello'

# バイト列の要素を取得する
print(b[0]) # 104
print(b[1]) # 101
print(b[2]) # 108
print(b[3]) # 108
print(b[4]) # 111
# バイト列を16進数の文字列に変換する
hex_str = b.hex()
print(hex_str) # 68656c6c6f

# 16進数の文字列からバイト列を作成する
new_b = bytes.fromhex(hex_str)
print(new_b) # b'hello'

バイト列は、バイナリファイルやネットワーク経由で送信されるデータの表現によく使われます。また、バイト列をテキストに変換する場合は、エンコーディング(符号化方式)を指定する必要があります。

Base64

Base64は、データをASCII文字列に変換するためのエンコーディング方式の1つであり、主にデータの転送や保存に使用されます。これは、バイナリデータをテキスト形式に変換する方法の1つであり、バイナリデータをテキストでやりとりできるようにします。

Base64では、8ビットのバイト列を6ビットのグループに分割し、各グループを基本となる64種類の文字のいずれかに変換します。この変換により、バイナリデータをテキスト形式のデータに変換することができます。Base64は、バイナリデータをASCII文字列に変換するだけでなく、文字列の安全な転送を保証するための機能も提供します。

Pythonでは、標準ライブラリのbase64モジュールを使用して、Base64エンコーディングとデコーディングを行うことができます。以下は、Base64エンコーディングの例です。

import base64

data = b'Hello, world!'
encoded_data = base64.b64encode(data)
print(encoded_data) # b'SGVsbG8sIHdvcmxkIQ=='

この例では、バイナリデータ b'Hello, world!' をBase64エンコードしています。エンコードされたデータはバイト列であり、文字列に変換するには、decode() メソッドを使用します。

print(encoded_data.decode()) # 'SGVsbG8sIHdvcmxkIQ=='

Base64デコーディングも同様に行うことができます。base64.b64decode() 関数を使用して、Base64エンコードされたデータを元のバイナリデータに戻すことができます。

decoded_data = base64.b64decode(encoded_data)
print(decoded_data) # b'Hello, world!'

cryptographyの暗号化と複合化

Pythonのcryptographyモジュールは、様々な暗号化アルゴリズムや署名・認証アルゴリズムを提供するライブラリです。以下では、cryptographyモジュールを使って文字列の暗号化と複合化を行う方法について説明します。

まずは、cryptographyモジュールをインストールします。

pip install cryptography

次に、Fernetという暗号化アルゴリズムを使って暗号化と複合化を行います。Fernetは、cryptographyモジュールで提供される対称鍵暗号アルゴリズムの一つです。

from cryptography.fernet import Fernet

# 鍵の生成
key = Fernet.generate_key()
print(key)
# Fernetオブジェクトの生成
fernet = Fernet(key)

# メッセージの暗号化
message = b"Hello, World!"
encrypted = fernet.encrypt(message)
print(encrypted)
# 暗号文の複合化
decrypted = fernet.decrypt(encrypted)
print(decrypted)

このコードでは、Fernet.generate_key()で鍵を生成し、Fernetオブジェクトを生成しています。暗号化はfernet.encrypt()、複合化はfernet.decrypt()で行います。

出力結果は以下のようになります。

b'y8qZKPgFZDpN9JjKuYZZYRv7VdUwFNbpK7VWupqCbsA='
b'gAAAAABgK1f4BpIvOmzohChlKfUkkETWU6P2vZI_kx6A9iO9bKmYQCYgNzEkm1UEaC29hyMhjvZC-9iz78NwiwekiMg-_q3y5w=='
b'Hello, World!'

暗号化されたデータはバイト列で、元のデータを含む平文とは異なる文字列になっています。

この例では、鍵はランダムに生成していますが、鍵を生成した後に他の人と共有する必要がある場合は、鍵をファイルに保存するなどの方法で別のプログラムで読み込めるようにする必要があります。また、平文や暗号化されたデータが改竄されていないかを確認するために、Fernetを使ってデータの署名や認証を行うこともできます。

hashlibのハッシュ

hashlib はPythonに組み込まれているハッシュ関数のモジュールです。ハッシュ関数とは、データを固定長の文字列に変換する関数です。ハッシュ値は、元のデータが変更された場合に検出するために使用されたり、パスワードなどの機密情報を格納する場合に使用されます。

hashlib には、SHA-1、SHA-224、SHA-256、SHA-384、SHA-512、MD5、blake2b、blake2sといった多くのハッシュアルゴリズムが用意されています。これらのアルゴリズムはすべて、同じ hashlib モジュールで利用可能です。

以下は、hashlib を使用してテキストをハッシュ化する例です。

import hashlib
text = "hello world"
hash_object = hashlib.sha256(text.encode())
print(hash_object.hexdigest())

出力:

f572d396fae9206628714fb2ce00f72e94f2258f8cd7863106c0ed3f8fa6a49b

この例では、hashlibsha256() メソッドを使用して、文字列 "hello world" をハッシュ化しています。encode() メソッドを使用して、文字列をバイト列に変換し、hexdigest() メソッドを使用して、ハッシュオブジェクトのハッシュ値を16進数の文字列として取得しています。


というわけで、今回は以上です。大変大変お疲れ様でした。
引き続きで、徐々に発信していきます。

コメントや感想を受け付けています。ちょっとした感想でもいいので嬉しいです。

それでは、以上です。

https://medical-science-labo.jp/python_advance07/

最新情報をチェックしよう!