Tag: kerberos

  • Kerberos

    Kerberos is a network authentication protocol that offers strong authentication for client/server applications using secret-key (symmetric) cryptography. It enables users, computers, and network services to securely verify each other’s identities over untrusted networks without the need to repeatedly transmit passwords.

    Developed at the Massachusetts Institute of Technology (MIT) as part of Project Athena, Kerberos is named after Cerberus, the three-headed dog from Greek mythology that guards the entrance to Hades. The name reflects its purpose of protecting access to network resources.

    Kerberos employs a trusted third party known as the Key Distribution Center (KDC) to manage authentication and issue encrypted tickets. Instead of sending user credentials every time someone accesses a network resource, Kerberos uses a ticket-based authentication mechanism to establish trust between clients and services.


    Kerberos Core Characteristics

    • Strong Authentication: This mechanism allows both clients and servers to securely verify each other’s identities using cryptographic methods, thereby preventing unauthorized access and impersonation.
    • Secret-Key Cryptography: This approach primarily uses symmetric encryption (secret-key cryptography) to secure authentication messages and tickets. Keys are typically derived from user passwords or securely managed for network services.
    • Ticket-Based System: After initial authentication, the user receives a Ticket Granting Ticket (TGT). This ticket enables the user to request service tickets for specific resources without the need to repeatedly transmit user credentials across the network.
    • Centralized Authentication: This system relies on a trusted central authority, known as the Key Distribution Center (KDC), which manages user identities, issues authentication tickets, and distributes session keys.
    • Time Synchronization: It is essential for client and server system clocks to be synchronized within an acceptable tolerance (usually a maximum difference of 5 minutes) to prevent replay attacks that exploit old timestamps.
    • Pre-authentication: Clients must provide cryptographic proof of their identity—such as a timestamp encrypted with their password hash—before the KDC issues a TGT. This step mitigates the risk of offline password-guessing dictionary attacks.
    • Mutual Authentication: This process allows both the client and the target server to verify each other’s identities, ensuring that the client is communicating with a legitimate service and not an imposter.

    Kerberos Components

    • Key Distribution Center (KDC): The central trust authority consisting of two logical sub-services:
      • Authentication Server (AS): Validates initial user credentials and issues Ticket Granting Tickets (TGTs).
      • Ticket Granting Service (TGS): Issues service tickets to clients presenting a valid TGT.
    • Client: The principal (user, workstation, or application) requesting access to a network service.
    • Server: The resource provider hosting the target service (e.g., file server, database, web application).
    • Ticket Granting Ticket (TGT): Issued by the AS after successful initial authentication. The KDC encrypts it with its internal master key for the TGS (historically known as the krbtgt account key). It proves the user’s authenticated identity to the TGS.
    • Service Ticket: Issued by the TGS and encrypted using the unique secret key shared exclusively between the KDC and the target service server. Presented by the client to access that specific service.
    • Session Key: Temporary cryptographic key used for secure communication

    Kerberos Workflow

    • Client Authentication (AS-REQ / AS-REP):
      • The client sends an initial authentication request to the Authentication Server (AS) containing its username (principal name) and pre-authentication data.
      • If valid, the AS responds with a TGT (encrypted with the TGS master key) and a client-TGS session key, with this response payload encrypted using a key derived from the user’s password.
    • Service Request (TGS-REQ):
      • When the client wants to access a service, it sends the TGT to the Ticket Granting Service (TGS) along with the target service’s principal name and an authenticator (a timestamp encrypted with the client-TGS session key to prove freshness).
    • Service Ticket Issuance (TGS-REP):
      • The TGS decrypts and validates the TGT and the authenticator.
      • If valid and the user is authorized, the TGS issues a Service Ticket (encrypted using the target service’s secret key) along with a new client-service session key.
    • Service Access & Mutual Authentication (AP-REQ / AP-REP):
      • The client presents the Service Ticket and a fresh authenticator to the destination application server.
      • The server decrypts the ticket using its own secret key, validates the authenticator, and grants access based on its access control policies.
      • Optionally, the server returns a reply to complete mutual authentication, proving to the client that it is the legitimate service.

    Real-world examples

    When an employee logs into a Windows domain computer, Active Directory authenticates the user and issues a Ticket Granting Ticket (TGT). Once the employee has the TGT, their computer can automatically use it to request a Service Ticket whenever they access network resources, such as a file share. This process enables secure, password-free Single Sign-On (SSO).

    1. Initial Login: The employee enters their username and password on their workstation.
    2. Authentication: Active Directory, acting as the Key Distribution Center (KDC), validates the credentials.
    3. TGT Issuance: The employee’s computer receives a Ticket Granting Ticket (TGT), which establishes a secure session.
    4. Resource Request: The employee tries to open a shared network folder hosted on a file server.
    5. Ticket Request: Behind the scenes, the computer uses the TGT to request a Service Ticket for the file server from the domain controller.
    6. Authorization: The file server decrypts and validates the ticket, granting access based on the employee’s permissions.

    John logs into his corporate workstation with his username and password, which the domain controller (Authentication Server) validates and uses to issue a Ticket Granting Ticket (TGT). When John tries to access the corporate email server, his computer presents the TGT to the Ticket Granting Service (TGS), which verifies his permissions and issues a service ticket, allowing him to access his email. Later, John attempts to access a restricted internal web server, but the TGS determines that he is not authorized to access that service and denies the request.

    1. Initial Login: John logs into his corporate workstation in the morning using his username (john) and password (123456).
    2. Authentication (AS): The domain controller validates John’s credentials and issues his Ticket Granting Ticket (TGT).
    3. Accessing the Email Server (Allowed):
      1. John opens his corporate email client.
      2. Behind the scenes, his computer presents his TGT to the Ticket Granting Service (TGS) and requests a service ticket for the emailserver.
      3. Because John is authorized for the email server, the TGS issues the ticket, and the email server authenticates him successfully.
    4. Accessing the Web Server (Denied):
      1. Later, John tries to access a restricted internal webserver (such as an administrative dashboard or secure portal).
      2. His computer requests a service ticket for the web server from the TGS using his TGT.
      3. The TGS checks John’s access control list, realizes he is not authorized for the web server, and denies the request ([Ticket Granting Service] Access Denied: User john is not authorized for webserver).

    import json # Used to serialize Python dictionaries into JSON and deserialize JSON back into dictionaries
    import secrets # Used to generate cryptographically secure random session keys
    import time # Used to manage ticket expiration timestamps
    from cryptography.fernet import Fernet # Provides symmetric encryption and decryption for Kerberos tickets

    class KerberosKDC:
        def __init__(self):
            self.users = {“john”: {“password”: “123456”}} # Simulated user database
            self.service_keys = {“emailserver”: Fernet.generate_key()} # Generate encryption key for the email server
            self.kdc_key = Fernet.generate_key() # Secret key used by the KDC to encrypt and decrypt TGTs

        def authenticate_user(self, username, password):
            if username not in self.users or self.users[username][“password”] != password: # Verify the user’s username and password
                print(“[Authentication Server] Invalid username or password”)
                return None
            session_key = secrets.token_hex(16) # Generate a random session key for the user
            tgt = {“username”: username, “session_key”: session_key, “expires”: time.time() + 3600} # Create a TGT containing user information, session key, and expiration time
            encrypted_tgt = self.encrypt_ticket(tgt, self.kdc_key) # Encrypt the TGT using the KDC secret key
            print(f”[Authentication Server] Issued TGT for {username}”)
            return encrypted_tgt # Return the encrypted TGT to the client

        def request_service_ticket(self, tgt, service):
            if tgt is None: # Check whether a TGT was provided
                return None
            tgt_data = self.decrypt_ticket(tgt, self.kdc_key) # Decrypt the TGT using the KDC secret key
            if tgt_data[“expires”] < time.time(): # Check whether the TGT has expired
                print(“[Ticket Granting Service] Ticket Granting Ticket (TGT) expired”)
                return None
            if service not in self.service_keys: # Verify that the requested service exists
                print(“[Ticket Granting Service] Service not found”)
                return None
            service_session_key = secrets.token_hex(16) # Generate a session key for communication with the requested service
            ticket = {“username”: tgt_data[“username”], “service”: service, “session_key”: service_session_key, “expires”: time.time() + 3600} # Create a service ticket with user information, session key, and expiration time
            encrypted_ticket = self.encrypt_ticket(ticket, self.service_keys[service]) # Encrypt the service ticket using the requested service’s secret key)
            print(f”[Ticket Granting Service] Issued service ticket for {service}”)
            return encrypted_ticket # Return the encrypted service ticket to the client

        def encrypt_ticket(self, data, key):
            cipher = Fernet(key) # Initialize Fernet encryption using the provided key
            serialized = json.dumps(data).encode(“utf-8”) # Convert the ticket dictionary into JSON and encode it as bytes
            return cipher.encrypt(serialized) # Encrypt the ticket and return the encrypted data

        def decrypt_ticket(self, ticket, key):
            cipher = Fernet(key) # Initialize Fernet decryption using the provided key
            decrypted = cipher.decrypt(ticket) # Decrypt the encrypted ticket
            return json.loads(decrypted.decode(“utf-8”)) # Decode the data and convert the JSON back into a Python dictionary

    class ServiceServer:
        def __init__(self, key):
            self.key = key # Store the secret key assigned to this service

        def authenticate(self, ticket):
            if ticket is None: # Check whether a service ticket was provided
                return False
            cipher = Fernet(self.key) # Initialize Fernet using the service’s secret key
            data = cipher.decrypt(ticket) # Decrypt the service ticket
            ticket_data = json.loads(data.decode(“utf-8”)) # Convert the decrypted JSON data into a Python dictionary
            if ticket_data[“expires”] < time.time(): # Verify that the service ticket has not expired
                print(“Service ticket expired”)
                return False
            print(f”Authenticated user: {ticket_data[‘username’]} for {ticket_data[‘service’]}”) # Display the authenticated username and requested service
            return True

    kdc = KerberosKDC() # Initialize the Key Distribution Center (KDC)
    print(“Accessing emailserver..”)
    tgt_john = kdc.authenticate_user(“john”, “123456”) # Authenticate John and obtain a Ticket Granting Ticket (TGT)
    ticket_john = kdc.request_service_ticket(tgt_john, “emailserver”) # Use the TGT to request a service ticket for the email server
    if ticket_john:
        email_server = ServiceServer(kdc.service_keys[“emailserver”]) # Initialize the email server with its secret key
        email_server.authenticate(ticket_john) # Validate the service ticket and authenticate John

    import json
    import secrets
    import time
    from cryptography.fernet import Fernet
    
    class KerberosKDC:
        def __init__(self):
            self.users = {"john": {"password": "123456"}}
            self.service_keys = {"emailserver": Fernet.generate_key()}
            self.kdc_key = Fernet.generate_key()
    
        def authenticate_user(self, username, password):
            if username not in self.users or self.users[username]["password"] != password:
                print("[Authentication Server] Invalid username or password")
                return None
            session_key = secrets.token_hex(16)
            tgt = {"username": username, "session_key": session_key, "expires": time.time() + 3600}
            encrypted_tgt = self.encrypt_ticket(tgt, self.kdc_key)
            print(f"[Authentication Server] Issued TGT for {username}")
            return encrypted_tgt
    
        def request_service_ticket(self, tgt, service):
            if tgt is None:
                return None
            tgt_data = self.decrypt_ticket(tgt, self.kdc_key)
            if tgt_data["expires"] < time.time():
                print("[Ticket Granting Service] Ticket Granting Ticket (TGT) expired")
                return None
            if service not in self.service_keys:
                print("[Ticket Granting Service] Service not found")
                return None
            service_session_key = secrets.token_hex(16)
            ticket = {"username": tgt_data["username"], "service": service, "session_key": service_session_key, "expires": time.time() + 3600}
            encrypted_ticket = self.encrypt_ticket(ticket, self.service_keys[service])
            print(f"[Ticket Granting Service] Issued service ticket for {service}")
            return encrypted_ticket
    
        def encrypt_ticket(self, data, key):
            cipher = Fernet(key)
            serialized = json.dumps(data).encode("utf-8")
            return cipher.encrypt(serialized)
    
        def decrypt_ticket(self, ticket, key):
            cipher = Fernet(key)
            decrypted = cipher.decrypt(ticket)
            return json.loads(decrypted.decode("utf-8"))
    
    class ServiceServer:
        def __init__(self, key):
            self.key = key
    
        def authenticate(self, ticket):
            if ticket is None:
                return False
            cipher = Fernet(self.key)
            data = cipher.decrypt(ticket)
            ticket_data = json.loads(data.decode("utf-8"))
            if ticket_data["expires"] < time.time():
                print("Service ticket expired")
                return False
            print(f"Authenticated user: {ticket_data['username']} for {ticket_data['service']}")
            return True
    
    kdc = KerberosKDC()
    print("Accessing emailserver..")
    tgt_john = kdc.authenticate_user("john", "123456")
    ticket_john = kdc.request_service_ticket(tgt_john, "emailserver")
    if ticket_john:
        email_server = ServiceServer(kdc.service_keys["emailserver"])
        email_server.authenticate(ticket_john)