Skip to main content
Loading...

More Python Posts

def parse_ike_proposal(proposal):
    """
    Parse an IKE or ESP proposal string to extract encryption, hash, and DH group in human-readable format.
    
    Args:
        proposal (str): IKE or ESP proposal string, e.g., 'IKE:AES_CBC_128/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_1024'
                        or 'IKE:AES_GCM_16_256/PRF_HMAC_SHA2_256/ECP_384' or 'ESP:AES_CBC_256/HMAC_SHA1_96/NO_EXT_SEQ'
    
    Returns:
        dict: Dictionary with encryption, hash, and DH group in human-readable format
    """
    dh_mapping = {
        # Standard MODP groups from RFC 2409 and RFC 3526
        'MODP_768': '1',   # 768-bit MODP group
        'MODP_1024': '2',  # 1024-bit MODP group
        'MODP_1536': '5',  # 1536-bit MODP group
        'MODP_2048': '14', # 2048-bit MODP group
        'MODP_3072': '15', # 3072-bit MODP group
        'MODP_4096': '16', # 4096-bit MODP group
        'MODP_6144': '17', # 6144-bit MODP group
        'MODP_8192': '18', # 8192-bit MODP group
        # Elliptic Curve groups from RFC 5114 and RFC 5903
        'ECP_256': '19',   # 256-bit ECP group
        'ECP_384': '20',   # 384-bit ECP group
        'ECP_521': '21',   # 521-bit ECP group
        'ECP_192': '25',   # 192-bit ECP group
        'ECP_224': '26',   # 224-bit ECP group
        # MODP groups with subgroup sizes from RFC 5114
        'MODP_1024_160': '22', # 1024-bit MODP with 160-bit subgroup
        'MODP_2048_224': '23', # 2048-bit MODP with 224-bit subgroup
        'MODP_2048_256': '24', # 2048-bit MODP with 256-bit subgroup
        # Additional groups from RFC 7919 (FFDHE - Finite Field Diffie-Hellman Ephemeral)
        'FFDHE_2048': '256', # 2048-bit FFDHE group
        'FFDHE_3072': '257', # 3072-bit FFDHE group
        'FFDHE_4096': '258', # 4096-bit FFDHE group
        'FFDHE_6144': '259', # 6144-bit FFDHE group
        'FFDHE_8192': '260', # 8192-bit FFDHE group
        # Brainpool curves from RFC 6954
        'BRAINPOOL_P256R1': '28', # 256-bit Brainpool curve
        'BRAINPOOL_P384R1': '29', # 384-bit Brainpool curve
        'BRAINPOOL_P512R1': '30', # 512-bit Brainpool curve
        # Modern elliptic curve groups from RFC 8031
        'CURVE25519': '31', # 256-bit elliptic curve (Curve25519, 128-bit security)
        'CURVE448': '32',   # 448-bit elliptic curve (Curve448, 224-bit security)
    }
    
    enc_mapping = {
        # AES in CBC mode (RFC 3602, commonly used in IPsec and TLS)
        'AES_CBC_128': 'AES-128',       # 128-bit key, CBC mode
        'AES_CBC_192': 'AES-192',       # 192-bit key, CBC mode
        'AES_CBC_256': 'AES-256',       # 256-bit key, CBC mode
        # AES in GCM mode (RFC 4106, authenticated encryption for IPsec/TLS)
        'AES_GCM_16_128': 'AES-GCM-128', # 128-bit key, GCM mode, 16-byte ICV
        'AES_GCM_16_192': 'AES-GCM-192', # 192-bit key, GCM mode, 16-byte ICV
        'AES_GCM_16_256': 'AES-GCM-256', # 256-bit key, GCM mode, 16-byte ICV
        'AES_GCM_8_128': 'AES-GCM-128-8', # 128-bit key, GCM mode, 8-byte ICV
        'AES_GCM_8_256': 'AES-GCM-256-8', # 256-bit key, GCM mode, 8-byte ICV
        'AES_GCM_12_128': 'AES-GCM-128-12', # 128-bit key, GCM mode, 12-byte ICV
        'AES_GCM_12_256': 'AES-GCM-256-12', # 256-bit key, GCM mode, 12-byte ICV
        # AES in CCM mode (RFC 4309, used in IPsec and some wireless protocols)
        'AES_CCM_16_128': 'AES-CCM-128', # 128-bit key, CCM mode, 16-byte ICV
        'AES_CCM_16_256': 'AES-CCM-256', # 256-bit key, CCM mode, 16-byte ICV
        # AES in CTR mode (RFC 3686, used in some VPNs and SSH)
        'AES_CTR_128': 'AES-CTR-128',   # 128-bit key, CTR mode
        'AES_CTR_192': 'AES-CTR-192',   # 192-bit key, CTR mode
        'AES_CTR_256': 'AES-CTR-256',   # 256-bit key, CTR mode
        # Legacy and alternative algorithms
        '3DES_CBC': '3DES',             # Triple DES, CBC mode (RFC 2451, deprecated)
        'DES_CBC': 'DES',               # Single DES, CBC mode (RFC 2405, obsolete)
        'CAMELLIA_CBC_128': 'CAMELLIA-128', # 128-bit Camellia, CBC mode (RFC 5529)
        'CAMELLIA_CBC_256': 'CAMELLIA-256', # 256-bit Camellia, CBC mode (RFC 5529)
        'CHACHA20_POLY1305': 'CHACHA20-POLY1305', # ChaCha20 with Poly1305 (RFC 8032, used in TLS 1.3, OpenVPN)
        'BLOWFISH_CBC': 'BLOWFISH',     # Blowfish, CBC mode (non-standard, used in some OpenSSH/OpenVPN)
        'CAST5_CBC': 'CAST5',           # CAST-128, CBC mode (non-standard, used in some OpenVPN)
        # Null encryption (for testing or integrity-only scenarios, RFC 2410)
        'NULL': 'NULL'                  # No encryption, only integrity protection
    }
    
    hash_mapping = {
        # Legacy hash algorithms (RFC 2403, RFC 2404, deprecated in modern systems)
        'HMAC_MD5': 'MD5',                 # MD5 HMAC, 128-bit output (insecure, legacy use in IPsec/SSH)
        'HMAC_MD5_96': 'MD5-96',           # MD5 HMAC, truncated to 96 bits (IPsec)
        'HMAC_SHA1': 'SHA1',               # SHA1 HMAC, 160-bit output (legacy, used in IPsec/TLS)
        'HMAC_SHA1_96': 'SHA1-96',         # SHA1 HMAC, truncated to 96 bits (IPsec)
        # SHA2-based HMAC algorithms (RFC 4868, used in IPsec, TLS, SSH)
        'HMAC_SHA2_256': 'SHA2-256',       # SHA2-256 HMAC, full 256-bit output
        'HMAC_SHA2_256_128': 'SHA2-256-128', # SHA2-256 HMAC, truncated to 128 bits
        'HMAC_SHA2_384': 'SHA2-384',       # SHA2-384 HMAC, full 384-bit output
        'HMAC_SHA2_384_192': 'SHA2-384-192', # SHA2-384 HMAC, truncated to 192 bits
        'HMAC_SHA2_512': 'SHA2-512',       # SHA2-512 HMAC, full 512-bit output
        'HMAC_SHA2_512_256': 'SHA2-512-256', # SHA2-512 HMAC, truncated to 256 bits
        # SHA3-based HMAC algorithms (RFC 8009, emerging in modern protocols)
        'HMAC_SHA3_224': 'SHA3-224',       # SHA3-224 HMAC, 224-bit output
        'HMAC_SHA3_256': 'SHA3-256',       # SHA3-256 HMAC, 256-bit output
        'HMAC_SHA3_384': 'SHA3-384',       # SHA3-384 HMAC, 384-bit output
        'HMAC_SHA3_512': 'SHA3-512',       # SHA3-512 HMAC, 512-bit output
        # Authenticated encryption integrity (used with AES-GCM/CCM, RFC 4106, RFC 4309)
        'AES_GMAC_128': 'GMAC-128',        # AES-GMAC with 128-bit key
        'AES_GMAC_192': 'GMAC-192',        # AES-GMAC with 192-bit key
        'AES_GMAC_256': 'GMAC-256',        # AES-GMAC with 256-bit key
        # Poly1305 (RFC 8032, used with ChaCha20 in TLS 1.3, OpenVPN)
        'POLY1305': 'POLY1305',            # Poly1305 authenticator, 128-bit output
        # Null authentication (RFC 2410, for testing or encryption-only scenarios)
        'NONE': 'NULL'                     # No integrity protection
    }
    
    # Split the proposal into components
    components = proposal.split('/')
    
    # Initialize result dictionary
    result = {
        'encryption': 'Unknown',
        'hash': 'None',  # Default to 'None' for AEAD ciphers like AES-GCM
        'dh_group': 'None'  # Default to 'None' for ESP or proposals without DH
    }
    
    # Extract components based on expected length
    if len(components) == 4:  # Standard IKE format: IKE:ENC/HASH/PRF/DH
        result['encryption'] = enc_mapping.get(components[0].replace('IKE:', ''), 'Unknown')
        result['hash'] = hash_mapping.get(components[1], 'Unknown')
        result['dh_group'] = dh_mapping.get(components[3], 'None')
    elif len(components) == 3:  # AEAD IKE format: IKE:ENC/PRF/DH or ESP:ENC/HASH/EXT
        result['encryption'] = enc_mapping.get(components[0].replace('IKE:', '').replace('ESP:', ''), 'Unknown')
        if components[0].startswith('IKE:') and components[1].startswith('PRF_'):  # AEAD IKE (e.g., AES-GCM)
            result['hash'] = 'None'
            result['dh_group'] = dh_mapping.get(components[2], 'None')
        else:  # ESP format (e.g., ESP:AES_CBC_256/HMAC_SHA1_96/NO_EXT_SEQ)
            result['hash'] = hash_mapping.get(components[1], 'Unknown')
            result['dh_group'] = 'None'  # ESP proposals typically lack DH groups
    
    return result
 
def process_proposals(proposal_list):
    """
    Process a list of IKE or ESP proposals, grouping by encryption and hash, and listing all DH groups.
    
    Args:
        proposal_list (str): Comma-separated string of IKE or ESP proposals
    
    Returns:
        dict: Dictionary mapping (encryption, hash) tuples to lists of DH groups
    """
    #print("PROPSOSAL LIST:", proposal_list)
    proposals = proposal_list.split(', ')
    grouped_proposals = {}
    
    for proposal in proposals:
        parsed = parse_ike_proposal(proposal.strip())
        key = (parsed['encryption'], parsed['hash'])
        dh_group = parsed['dh_group']
        
        if key not in grouped_proposals:
            grouped_proposals[key] = []
        if dh_group != 'None' and dh_group not in grouped_proposals[key]:
            grouped_proposals[key].append(dh_group)
    
    # Sort DH groups for consistency (numerically by group number)
    for key in grouped_proposals:
        grouped_proposals[key].sort(key=lambda x: int(x))
    
    # Format output as strings
    result = []
    for (enc, hash_val), dh_groups in grouped_proposals.items():
        hash_part = f" Hash {hash_val}" if hash_val != 'None' else ""
        dh_group_part = f" DH Group(s) {' '.join(dh_groups)}" if dh_groups else " DH Group(s) None"
        result.append(f"Encryption {enc}{hash_part}{dh_group_part}")
    
    return result
 
# Example usage
if __name__ == "__main__":
    proposals = """IKE:AES_CBC_128/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_1024, IKE:AES_CBC_128/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_2048, IKE:AES_CBC_128/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_3072, IKE:AES_CBC_128/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_4096, IKE:AES_CBC_128/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_6144, IKE:AES_CBC_128/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_8192, IKE:AES_CBC_128/HMAC_SHA1_96/PRF_HMAC_SHA1/ECP_256, IKE:AES_CBC_128/HMAC_SHA1_96/PRF_HMAC_SHA1/ECP_384, IKE:AES_CBC_128/HMAC_SHA1_96/PRF_HMAC_SHA1/ECP_521, IKE:AES_CBC_128/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_1024_160, IKE:AES_CBC_128/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_2048_224, IKE:AES_CBC_128/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_2048_256, IKE:AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_1024, IKE:AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_2048, IKE:AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_3072, IKE:AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_4096, IKE:AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_6144, IKE:AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_8192, IKE:AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/ECP_256, IKE:AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/ECP_384, IKE:AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/ECP_521, IKE:AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_1024_160, IKE:AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_2048_224, IKE:AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_2048_256, IKE:AES_CBC_128/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_1024, IKE:AES_CBC_128/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_2048, IKE:AES_CBC_128/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_3072, IKE:AES_CBC_128/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_4096, IKE:AES_CBC_128/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_6144, IKE:AES_CBC_128/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_8192, IKE:AES_CBC_128/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/ECP_256, IKE:AES_CBC_128/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/ECP_384, IKE:AES_CBC_128/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/ECP_521, IKE:AES_CBC_128/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_1024_160, IKE:AES_CBC_128/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_2048_224, IKE:AES_CBC_128/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_2048_256, IKE:AES_CBC_128/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_1024, IKE:AES_CBC_128/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_2048, IKE:AES_CBC_128/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_3072, IKE:AES_CBC_128/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_4096, IKE:AES_CBC_128/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_6144, IKE:AES_CBC_128/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_8192, IKE:AES_CBC_128/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/ECP_256, IKE:AES_CBC_128/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/ECP_384, IKE:AES_CBC_128/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/ECP_521, IKE:AES_CBC_128/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_1024_160, IKE:AES_CBC_128/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_2048_224, IKE:AES_CBC_128/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_2048_256, IKE:AES_CBC_256/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_1024, IKE:AES_CBC_256/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_2048, IKE:AES_CBC_256/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_3072, IKE:AES_CBC_256/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_4096, IKE:AES_CBC_256/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_6144, IKE:AES_CBC_256/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_8192, IKE:AES_CBC_256/HMAC_SHA1_96/PRF_HMAC_SHA1/ECP_256, IKE:AES_CBC_256/HMAC_SHA1_96/PRF_HMAC_SHA1/ECP_384, IKE:AES_CBC_256/HMAC_SHA1_96/PRF_HMAC_SHA1/ECP_521, IKE:AES_CBC_256/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_1024_160, IKE:AES_CBC_256/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_2048_224, IKE:AES_CBC_256/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_2048_256, IKE:AES_CBC_256/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_1024, IKE:AES_CBC_256/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_2048, IKE:AES_CBC_256/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_3072, IKE:AES_CBC_256/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_4096, IKE:AES_CBC_256/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_6144, IKE:AES_CBC_256/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_8192, IKE:AES_CBC_256/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/ECP_256, IKE:AES_CBC_256/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/ECP_384, IKE:AES_CBC_256/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/ECP_521, IKE:AES_CBC_256/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_1024_160, IKE:AES_CBC_256/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_2048_224, IKE:AES_CBC_256/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_2048_256, IKE:AES_CBC_256/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_1024, IKE:AES_CBC_256/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_2048, IKE:AES_CBC_256/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_3072, IKE:AES_CBC_256/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_4096, IKE:AES_CBC_256/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_6144, IKE:AES_CBC_256/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_8192, IKE:AES_CBC_256/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/ECP_256, IKE:AES_CBC_256/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/ECP_384, IKE:AES_CBC_256/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/ECP_521, IKE:AES_CBC_256/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_1024_160, IKE:AES_CBC_256/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_2048_224, IKE:AES_CBC_256/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_2048_256, IKE:AES_CBC_256/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_1024, IKE:AES_CBC_256/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_2048, IKE:AES_CBC_256/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_3072, IKE:AES_CBC_256/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_4096, IKE:AES_CBC_256/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_6144, IKE:AES_CBC_256/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_8192, IKE:AES_CBC_256/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/ECP_256, IKE:AES_CBC_256/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/ECP_384, IKE:AES_CBC_256/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/ECP_521, IKE:AES_CBC_256/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_1024_160, IKE:AES_CBC_256/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_2048_224, IKE:AES_CBC_256/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_2048_256"""
    
 
    proposals_result = '\n'.join(process_proposals(proposals))
    print(f"AWS tunnel is processing proposals to find a matching configuration. AWS tunnel is configured as follows:\n\n{proposals_result}")
# Python program for Plotting Fibonacci 
# spiral fractal using Turtle 
import turtle 
import math 
  
def fiboPlot(n): 
    a = 0
    b = 1
    square_a = a 
    square_b = b 
  
    # Setting the colour of the plotting pen to blue 
    x.pencolor("blue") 
  
    # Drawing the first square 
    x.forward(b * factor) 
    x.left(90) 
    x.forward(b * factor) 
    x.left(90) 
    x.forward(b * factor) 
    x.left(90) 
    x.forward(b * factor) 
  
    # Proceeding in the Fibonacci Series 
    temp = square_b 
    square_b = square_b + square_a 
    square_a = temp 
      
    # Drawing the rest of the squares 
    for i in range(1, n): 
        x.backward(square_a * factor) 
        x.right(90) 
        x.forward(square_b * factor) 
        x.left(90) 
        x.forward(square_b * factor) 
        x.left(90) 
        x.forward(square_b * factor) 
  
        # Proceeding in the Fibonacci Series 
        temp = square_b 
        square_b = square_b + square_a 
        square_a = temp 
  
    # Bringing the pen to starting point of the spiral plot 
    x.penup() 
    x.setposition(factor, 0) 
    x.seth(0) 
    x.pendown() 
  
    # Setting the colour of the plotting pen to red 
    x.pencolor("red") 
  
    # Fibonacci Spiral Plot 
    x.left(90) 
    for i in range(n): 
        print(b) 
        fdwd = math.pi * b * factor / 2
        fdwd /= 90
        for j in range(90): 
            x.forward(fdwd) 
            x.left(1) 
        temp = a 
        a = b 
        b = temp + b 
  
  
# Here 'factor' signifies the multiplicative  
# factor which expands or shrinks the scale 
# of the plot by a certain factor. 
factor = 1
  
# Taking Input for the number of  
# Iterations our Algorithm will run 
n = int(input('Enter the number of iterations (must be > 1): ')) 
  
# Plotting the Fibonacci Spiral Fractal  
# and printing the corresponding Fibonacci Number 
if n > 0: 
    print("Fibonacci series for", n, "elements :") 
    x = turtle.Turtle() 
    x.speed(100) 
    fiboPlot(n) 
    turtle.done() 
else: 
    print("Number of iterations must be > 0")
def format_timestamp(timestamp_epoch):
    """
    Convert epoch timestamp to formatted datetime string without using datetime package.
    
    Args:
        timestamp_epoch (int/float): Unix epoch timestamp (seconds since 1970-01-01 00:00:00 UTC)
        
    Returns:
        str: Formatted datetime string in 'YYYY-MM-DD HH:MM:SS' format
    """
    # Constants for time calculations
    SECONDS_PER_DAY = 86400
    SECONDS_PER_HOUR = 3600
    SECONDS_PER_MINUTE = 60
    
    # Handle negative timestamps and convert to integer
    timestamp = int(timestamp_epoch)
    
    # Calculate days since epoch and remaining seconds
    days_since_epoch = timestamp // SECONDS_PER_DAY
    remaining_seconds = timestamp % SECONDS_PER_DAY
    
    # Calculate hours, minutes, seconds
    hours = remaining_seconds // SECONDS_PER_HOUR
    remaining_seconds %= SECONDS_PER_HOUR
    minutes = remaining_seconds // SECONDS_PER_MINUTE
    seconds = remaining_seconds % SECONDS_PER_MINUTE
    
    # Calculate date (simplified, ignoring leap seconds)
    year = 1970
    days = days_since_epoch
    while days >= 365:
        is_leap = (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0)
        days_in_year = 366 if is_leap else 365
        if days >= days_in_year:
            days -= days_in_year
            year += 1
    
    # Month lengths (non-leap year for simplicity, adjusted later for leap years)
    month_lengths = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    if (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0):
        month_lengths[1] = 29
    
    month = 0
    while days >= month_lengths[month]:
        days -= month_lengths[month]
        month += 1
    
    # Convert to 1-based indexing for month and day
    month += 1
    day = days + 1
    
    # Format the output string
    return f"{year:04d}-{month:02d}-{day:02d} {hours:02d}:{minutes:02d}:{seconds:02d}"

# Example timestamp (Unix epoch seconds)
timestamp = 1697054700
formatted_date = format_timestamp(timestamp)
print(formatted_date + " UTC")  # Output: 2023-10-11 18:45:00