How to Convert PUTTYgen SSH2 Public Key Format to OpenSSH Format for authorized_keys


1 views

When working with SSH public keys, you'll encounter two common formats:

# Format 1 (SSH2 format typically from PUTTYgen)
---- BEGIN SSH2 PUBLIC KEY ----
Comment: "somename-20060227"
AAAAB3NzaC1yc2EAAAABJQAAAIBmhLUTJiP[and so on]==
---- END SSH2 PUBLIC KEY ----

# Format 2 (OpenSSH format from ssh-keygen)
ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAqof[and so on] user@host

The OpenSSH authorized_keys file expects the one-line format (like Format 2). The SSH2 format from PUTTYgen won't work if directly pasted into the file.

Method 1: Using PUTTYgen (GUI)

  1. Open PUTTYgen
  2. Load your private key (.ppk file)
  3. Copy the public key from the "Public key for pasting..." text area

Method 2: Using ssh-keygen (Command Line)

If you have the private key in OpenSSH format:

ssh-keygen -y -f ~/.ssh/id_rsa > ~/.ssh/id_rsa.pub

Method 3: Manual Conversion

For an existing SSH2 format key:

# Strip headers, footers, and comments
# Keep only the base64 portion
# Prepend the key type (usually ssh-rsa)
# Example transformation:
ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIBmhLUTJiP[original key data]

After conversion, verify the key:

ssh-keygen -l -f your_key.pub

This should show the key fingerprint without errors.

Complete example for converting a PUTTYgen key:

# Original SSH2 format
---- BEGIN SSH2 PUBLIC KEY ----
Comment: "dev-server-2023"
AAAAB3NzaC1yc2EAAAABJQAAAQEAqof[truncated]==
---- END SSH2 PUBLIC KEY ----

# Converted OpenSSH format
ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAqof[truncated] dev-server-2023
  • Ensure no line breaks in the final key
  • Check for proper key type prefix (ssh-rsa, ssh-ed25519, etc.)
  • Verify the key hasn't been corrupted during copy-paste

When working with SSH public keys, you'll encounter two primary formats:

# Format 1 (PuTTYgen style)
---- BEGIN SSH2 PUBLIC KEY ----
Comment: "somename-20060227"
AAAAB3NzaC1yc2EAAAABJQAAAIBmhLUTJiP[and so on]==
---- END SSH2 PUBLIC KEY ----

# Format 2 (OpenSSH style)
ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAqof[and so on]

The OpenSSH authorized_keys file specifically requires keys in the single-line format. While PuTTYgen's format is valid for Windows clients, it won't work when pasted directly into authorized_keys.

Method 1: Using PuTTYgen

If you have access to the original .ppk file:

  1. Open PuTTYgen
  2. Load your private key
  3. Copy the public key from the top textarea (already in OpenSSH format)

Method 2: Manual Conversion

For existing public keys in PuTTYgen format:

# Strip headers/footers and keep only the base64 part
AAAAB3NzaC1yc2EAAAABJQAAAIBmhLUTJiP[and so on]==

# Then prefix with key type (rsa/dsa/ecdsa)
ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIBmhLUTJiP[and so on]==

Method 3: Using ssh-keygen

If you have the private key:

ssh-keygen -y -f id_rsa > id_rsa.pub

After conversion, check the format:

ssh-keygen -l -f converted_key.pub

Should output fingerprint information if the format is correct.

Here's a Python script to automate the conversion:

import re

def convert_putty_to_openssh(putty_key):
    # Extract base64 portion
    match = re.search(r'([A-Za-z0-9+/=]{30,})', putty_key)
    if not match:
        raise ValueError("Invalid PuTTY public key format")
    
    # Assume RSA unless specified otherwise
    key_type = "ssh-rsa"
    if "dsa" in putty_key.lower():
        key_type = "ssh-dss"
    elif "ecdsa" in putty_key.lower():
        key_type = "ecdsa-sha2-nistp256"
    
    return f"{key_type} {match.group(1)}"

# Example usage
putty_key = """---- BEGIN SSH2 PUBLIC KEY ----
Comment: "somename-20060227"
AAAAB3NzaC1yc2EAAAABJQAAAIBmhLUTJiP[and so on]==
---- END SSH2 PUBLIC KEY ----"""

print(convert_putty_to_openssh(putty_key))
  • Extra whitespace in authorized_keys (must be exactly one line)
  • Missing key type prefix
  • Corrupted base64 data during copy-paste
  • Windows line endings (CRLF instead of LF)

For more robust conversion, you can decode the base64 portion to determine the actual key type:

import base64
import struct

def get_key_type(blob):
    # Decode base64 and read initial length
    decoded = base64.b64decode(blob)
    key_type_len = struct.unpack('>I', decoded[:4])[0]
    return decoded[4:4+key_type_len].decode('ascii')