簡體   English   中英

cryptography.exceptions.InvalidSignature:簽名與摘要不匹配

[英]cryptography.exceptions.InvalidSignature: Signature did not match digest

我寫了一個 KDC 服務器的例子,使用 package cryptography.fe.net。

我不明白為什么有時它會隨機運行,有時會以異常結束: cryptography.exceptions.InvalidSignature:簽名與摘要不匹配。

密鑰在主程序啟動時創建一次。 所以這個問題似乎與創建不同的隨機密鑰無關。

任何人都可以幫我檢測出什么問題了嗎?

from cryptography.fernet import Fernet
import uuid
import pickle

def generate_challenge():
  return uuid.uuid4().bytes

def serialize(o):
  return pickle.dumps(o)

def deserialize(o):
  return pickle.loads(o)

class InitiateRequest:
  def __init__(self, initiator, responder, challenge):
    self.initiator = initiator    # IDa
    self.responder = responder    # IDb
    self.challenge =  challenge   # N1

class InitiateResponse:
  def __init__(self, session_key, initiator, responder, challenge):
    self.session_key = session_key  # Ks
    self.initiator = initiator      # IDa
    self.responder = responder      # IDb
    self.challenge = challenge      # N1

class InvitationForward:
  def __init__(self, session_key, initiator):
    self.session_key = session_key  # Ks
    self.initiator = initiator      # IDa

class KDCServer:
  def __init__(self, generator: Fernet):
    self.generator = generator
    self.map_keys = {} # user+key pairs

  def subscribe(self, id, key):
    self.map_keys[id] = key
    print("KDCServer: I'm registering key " + str(key) + " for " + id)

  def issue_session_key(self, r: InitiateRequest):
    session_key = self.generator.generate_key()
    response = InitiateResponse(session_key, r.initiator, r.responder, r.challenge) 
    invitation = InvitationForward(session_key, r.initiator)
    print(self.map_keys)
    print("KDCServer: I'm using " + str(self.map_keys[r.initiator]) + " as keyA_KDC")
    keyA_KDC = Fernet(self.map_keys[r.initiator]) 
    print("KDCServer: I'm using " + str(self.map_keys[r.responder]) + " as keyB_KDC")
    keyB_KDC = Fernet(self.map_keys[r.responder])
    print("KDCServer: I've just issued a session key for " + r.initiator + " and " + r.responder)
    return {
        keyA_KDC.encrypt(serialize(response)),   # E(Ka,[Ks|IDa|IDb|N1])
        keyB_KDC.encrypt(serialize(invitation))  # E(Kb,[Ks|IDa])
    }

class User:

  def __init__(self, id:str, key:bytes):
    self.id = id
    self.key = key
    self.session_keys = {}

  def initiate(self, responder):
    challenge = generate_challenge()
    print(self.id + ": Let's retrieve a session key to communicate with " + responder)
    # store request for matching
    self.request = InitiateRequest(self.id, responder, challenge)
    return self.request

  def match_request(self, check:InitiateResponse)->bool:
      return (self.request.challenge == check.challenge) and (self.request.initiator == check.initiator) and (self.request.responder == check.responder)
  
  def accept_response(self, response):
    print(self.id + ": I'm decrypting using my key " + str(self.key))
    check = deserialize(Fernet(self.key).decrypt(response))
    if self.match_request(check):
      self.session_keys[check.responder] = check.session_key # save session key Ks
      print(self.id + ": I've got the session key to communicate with " + check.responder)

  def accept_invitation(self, invitation):
    check = deserialize(Fernet(self.key).decrypt(invitation))
    print(self.id + ": I've accepted the invitation from " + check.initiator)
    self.session_keys[check.initiator] = check.session_key # save session key Ks

  def send_message(self, message, receiver):
    print(self.id + ": I'm sending this message " + str(message) + " using the session key " + str(self.session_keys[receiver]))
    return Fernet(self.session_keys[receiver]).encrypt(message)

  def receive_message(self, cyphered, sender):
    print(self.id + ": I'm decrypting a message using the session key " + str(self.session_keys[sender]))
    message = Fernet(self.session_keys[sender]).decrypt(cyphered)
    print(self.id + ": I've received the message " + str(message) + " from " + sender)

def main():
  alice_key = Fernet.generate_key()
  bob_key = Fernet.generate_key()

  alice = User('Alice', alice_key)
  bob = User('Bob', bob_key)

  server = KDCServer(Fernet)
  server.subscribe(alice.id, alice_key)
  server.subscribe(bob.id, bob_key)

  # Alice sends request to KDC to get a session key
  request = alice.initiate(bob.id)
  response, invitation = server.issue_session_key(request)

  # Alice accepts response from KDC and forwards invitation to Bob
  alice.accept_response(response)
  # Bob accepts invitation from Alice
  bob.accept_invitation(invitation)

  cyphered = bob.send_message(b"My secret message", alice.id)
  alice.receive_message(cyphered, bob.id)

if __name__ == "__main__":
    main()

問題是由issue_session_key()中返回的Set引起的。 Python Set是無序的,因此responseinvitation將在 50% 的時間內在main()中交換,從而導致錯誤。 使用例如Tuple而不是Set Python 元組是有序的:

...
return (
    keyA_KDC.encrypt(serialize(response)),   # E(Ka,[Ks|IDa|IDb|N1])
    keyB_KDC.encrypt(serialize(invitation))  # E(Kb,[Ks|IDa])
)
...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM