2023年12月24日 星期日

使用cryptography套件來進行數位簽章

 

程式設計說明:

利用 Python 程式碼使用 cryptography 函式庫來實現了數位簽章(Digital Signature)的功能。首先,先成金鑰對(generate_key_pair),再依照上圖來簽署訊息(sign_message)和驗證簽章(verify_signature),來實現三個函式,說明如下:

1.生成金鑰對(generate_key_pair):

  • 使用 rsa.generate_private_key 函數生成一對私鑰(private_key)和公鑰(public_key)。
  • 公鑰通常用於驗證數位簽章,私鑰用於創建數位簽章。
2.簽署訊息(sign_message):
  • 使用私鑰對給定的訊息(message)進行數位簽章。
  • 簽章過程使用了 PSS padding 和 SHA-256 hash 函數。
3.驗證簽章(verify_signature):
  • 使用公鑰對簽章進行驗證,確保簽章是由對應的私鑰創建的。
  • 如果驗證成功,返回 True,否則捕捉例外並輸出錯誤訊息,然後返回 False。

程式碼如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import rsa, padding

def generate_key_pair():
    private_key = rsa.generate_private_key(
        public_exponent=65537,
        key_size=2048,
        backend=default_backend()
    )
    public_key = private_key.public_key()
    return private_key, public_key

def sign_message(private_key, message):
    signature = private_key.sign(
        message.encode('utf-8'),
        padding.PSS(
            mgf=padding.MGF1(hashes.SHA256()),
            salt_length=padding.PSS.MAX_LENGTH
        ),
        hashes.SHA256()
    )
    return signature

def verify_signature(public_key, message, signature):
    try:
        public_key.verify(
            signature,
            message.encode('utf-8'),
            padding.PSS(
                mgf=padding.MGF1(hashes.SHA256()),
                salt_length=padding.PSS.MAX_LENGTH
            ),
            hashes.SHA256()
        )
        return True
    except Exception as e:
        print(f"驗證失敗: {e}")
        return False

# Example usage:
private_key, public_key = generate_key_pair()
message_to_sign = "虎尾鎮,舊稱「大崙腳」,位於臺灣雲林縣中心,是一個因糖廠而興起的城鎮。"

signature = sign_message(private_key, message_to_sign)
print(f"數位簽章: {signature.hex()}")

if verify_signature(public_key, message_to_sign, signature):
    print("有效的數位簽章")
else:
    print("無效的數位簽章")

第一次執行結果:
數位簽章: 7006f8b687e8a0b93915822731f5bd74833a1bfc1b4bb610dbee5c6eb5ed5b99059ec9a7a6727b6dfffeb7f772079ada05f9c804abc31b13834429c1b4cc5b82719f08f6665a05211205f5f74365e0eb19f543c02139d09417fe1a7befd248face6ae8e9173d5b6a9ac5347ca0fad9fce0f5df3e7949811c786e0ff1ce389074f2e15bdf44efd46a3e420079312bad276a0322a95a538518828e9c6fa6f2cb392776ad6768524628721f311a4f7f41a8cb6019c6ff7668fe4fc96c2d64a24f43891144a96bf68e9373a26813beea80943b2a9c3bc69f966689e9c8ef93d0dfb5115b93308621b8024c9e591132fcc59cfa2dffbd6090f0f65027ab61a53e6564
有效的數位簽章

第二次執行結果:
數位簽章: 64c1c967c1f3e2866d3e4fb724e0fb74401e623be0c0f14d07ae6569edf09ca509613aa051ef5e467b6548fa6084f61fa067812832f1eabb750a1454e082cb9c03886f4e68958bdba785d3dac4a2405b3bf79e47f769c6d5b1a4dca782a280ec81337ce30b7104230058c7b61f97f2793a6b1ef63b685a59c355f05b1a9dd822094685c8445269540063120ca84356017ef3bdcf74fc4176e7704a794bb508764eb09cea3f491daac4f8adb3b958a10c279c056331147d9d0c712003bdb0a2366c487576e2916fc3fe111086c9630fbcad207a04b4f2773234248cccbbf7b191d2928fcb7db38c82f8611373b5c7843681d955a290e0784e7213ccf580bd6fae
有效的數位簽章

以上兩次執行會發現數位簽章都不同,但執行結果是一樣的,都是有效的數位簽章。

若在第47行插入下列程式:
message_to_sign = "虎尾鎮是一個因糖廠而興起的城鎮。"

修改後的程式碼如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import rsa, padding

def generate_key_pair():
    private_key = rsa.generate_private_key(
        public_exponent=65537,
        key_size=2048,
        backend=default_backend()
    )
    public_key = private_key.public_key()
    return private_key, public_key

def sign_message(private_key, message):
    signature = private_key.sign(
        message.encode('utf-8'),
        padding.PSS(
            mgf=padding.MGF1(hashes.SHA256()),
            salt_length=padding.PSS.MAX_LENGTH
        ),
        hashes.SHA256()
    )
    return signature

def verify_signature(public_key, message, signature):
    try:
        public_key.verify(
            signature,
            message.encode('utf-8'),
            padding.PSS(
                mgf=padding.MGF1(hashes.SHA256()),
                salt_length=padding.PSS.MAX_LENGTH
            ),
            hashes.SHA256()
        )
        return True
    except Exception as e:
        print(f"驗證失敗: {e}")
        return False

# Example usage:
private_key, public_key = generate_key_pair()
message_to_sign = "虎尾鎮,舊稱「大崙腳」,位於臺灣雲林縣中心,是一個因糖廠而興起的城鎮。"

signature = sign_message(private_key, message_to_sign)
print(f"數位簽章: {signature.hex()}")
message_to_sign = "虎尾鎮是一個因糖廠而興起的城鎮。"
if verify_signature(public_key, message_to_sign, signature):
    print("有效的數位簽章")
else:
    print("無效的數位簽章")

執行結果:
數位簽章: 2498811122ad6bd65cfd4fcaee18c30cc75ee3007571ab8c17438cbc8b4ef1c347df20866c0e77ced3d63d19bb5a2dc87362ea76a6050429b19538ec5f416c6ea058ffc5c003e95f0aa06c15a29869190e438a72a216b226470bd5652bdc2a9949a6b51159a574eb9cfcddb77fa11617d11dcc9e55c3711088079da8bb06d80a658dc041bde272e2a1bd96a0eb80561410701aed2f22d93e68ea71a390e391093f43d9a8952005e526c174c406d9b5624298d105854282d9cf116d246075cc0b748b5f75ec7f0d860757ae16cf860c1791cef2ba3fab6a52bf6ec45c171d7cd38f5360dba55c0d23ed3e837ccc639bec923f207cc71ba9f42fbff6905fe714d7
驗證失敗: 
無效的數位簽章

以上範例告訴我們若文件內容被修改,則驗證將失敗。

沒有留言:

張貼留言