regluit/ssh_fingerprint.ipynb

457 lines
15 KiB
Plaintext

{
"metadata": {
"name": "ssh_fingerprint"
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Purpose**: to figure out exactly how to calculate the various (two?) ssh fingerprints used in configuring and running Amazon EC2\n",
"\n",
"http://blog.jbrowne.com/?p=23#comment-3393\n",
"\n",
"> `openssl pkey -in ~/.ssh/id_rsa -pubout -outform DER | openssl md5 -c`\n",
"\n",
"does work to calculate the fingerprint of my key:\n",
"\n",
"> `ac:89:8d:0c:df:31:56:ee:6e:78:1d:1e:93:00:52:2d`\n",
"\n",
"gets us from the **private key** to the fingerprint. Question is how to go from the public key to the fingerprint."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Documentation I used\n",
"\n",
"* http://stackoverflow.com/questions/1193529/how-to-store-retreieve-rsa-public-private-key/13104466#13104466\n",
"* http://blog.oddbit.com/post/converting-openssh-public-keys"
]
},
{
"cell_type": "heading",
"level": 1,
"metadata": {},
"source": [
"Working solution using pycrypto"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"from Crypto.PublicKey import RSA\n",
"import hashlib\n",
"import binascii\n",
"\n",
"#ID_RSA_PUB = \"/Users/raymondyee/.ssh/id_rsa.pub\"\n",
"ID_RSA_PUB = \"/Users/raymondyee/Downloads/bitnami_id_rsa.pub\"\n",
"\n",
"f = open(ID_RSA_PUB,'r')\n",
"key = RSA.importKey(f.read())\n",
"\n",
"m = hashlib.md5()\n",
"m.update(key.exportKey(format='DER'))\n",
"\n",
"print \":\".join([binascii.hexlify(x) for x in m.digest()])"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"ac:89:8d:0c:df:31:56:ee:6e:78:1d:1e:93:00:52:2d\n"
]
}
],
"prompt_number": 1
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# a public key is composed for exponent and the modulus\n",
"\n",
"key.key.e, key.key.n"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 2,
"text": [
"(35L,\n",
" 30114135277653090823710484015151796817301617075400240733128040544798698312920588403463603981769886992554796191996568892528138169118348632322047720739395956375745657272649606919479336601099168464203766012976604168428018544914226059685223932713785609109017712489953083792700211168583351462038902385714547623938709628695910501393773400681613556201339040761453113553103960871996644827110383060821448637902191317722721525710636601653187146323206401122522925096379961686500366444811043089699319022690405787790577166939257312013881740342345310346038558933025283068006936847503423602798229680773428578097891321345458334787503L)"
]
}
],
"prompt_number": 2
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# https://github.com/dlitz/pycrypto/blob/v2.6/lib/Crypto/PublicKey/RSA.py#L308\n",
"\n",
"key.exportKey('PEM')"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 17,
"text": [
"'-----BEGIN PUBLIC KEY-----\\nMIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEA7ozGYIwEEXj10hAICsy+\\nqdBHYbV95cs7rSR8ZG+6te2aPL1Pg0e5lUJkyMao0T//LfFNBRwg0wqWsb7b6yUv\\nXmJAD3r5hjTCWlKJ/54APxInT/YMi08GVwSnwgVnib8zmjmfJ+6zFj5MsPTNPsdL\\n/DWxheyZ0oHDxL0rpcL192sdgu4//5j0oyk+w/rrm+jUMNpuOOGPINMZxEd6+OMX\\nr239ZLGSkWAavtMW1FKOXc/qrLHn03rNdz4cHZ1Gsx2++d8lk4jf8BzC0t3XXVuR\\nZNu8lhlzCMW6sUEG6uACnXYlnmQg597fcVUFXmdQ4I79PGndjy35FwdbmiLLe+bn\\nrwIBIw==\\n-----END PUBLIC KEY-----'"
]
}
],
"prompt_number": 17
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"print key.exportKey('OpenSSH')"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA7ozGYIwEEXj10hAICsy+qdBHYbV95cs7rSR8ZG+6te2aPL1Pg0e5lUJkyMao0T//LfFNBRwg0wqWsb7b6yUvXmJAD3r5hjTCWlKJ/54APxInT/YMi08GVwSnwgVnib8zmjmfJ+6zFj5MsPTNPsdL/DWxheyZ0oHDxL0rpcL192sdgu4//5j0oyk+w/rrm+jUMNpuOOGPINMZxEd6+OMXr239ZLGSkWAavtMW1FKOXc/qrLHn03rNdz4cHZ1Gsx2++d8lk4jf8BzC0t3XXVuRZNu8lhlzCMW6sUEG6uACnXYlnmQg597fcVUFXmdQ4I79PGndjy35FwdbmiLLe+bnrw==\n"
]
}
],
"prompt_number": 4
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"import base64"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 5
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"id_rsa_pub = open(ID_RSA_PUB).read()"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 6
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"id_rsa_pub.split(None)[1]"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 7,
"text": [
"'AAAAB3NzaC1yc2EAAAABIwAAAQEA7ozGYIwEEXj10hAICsy+qdBHYbV95cs7rSR8ZG+6te2aPL1Pg0e5lUJkyMao0T//LfFNBRwg0wqWsb7b6yUvXmJAD3r5hjTCWlKJ/54APxInT/YMi08GVwSnwgVnib8zmjmfJ+6zFj5MsPTNPsdL/DWxheyZ0oHDxL0rpcL192sdgu4//5j0oyk+w/rrm+jUMNpuOOGPINMZxEd6+OMXr239ZLGSkWAavtMW1FKOXc/qrLHn03rNdz4cHZ1Gsx2++d8lk4jf8BzC0t3XXVuRZNu8lhlzCMW6sUEG6uACnXYlnmQg597fcVUFXmdQ4I79PGndjy35FwdbmiLLe+bnrw=='"
]
}
],
"prompt_number": 7
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"s = base64.b64decode(id_rsa_pub.split(None)[1])"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 8
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"s"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 9,
"text": [
"'\\x00\\x00\\x00\\x07ssh-rsa\\x00\\x00\\x00\\x01#\\x00\\x00\\x01\\x01\\x00\\xee\\x8c\\xc6`\\x8c\\x04\\x11x\\xf5\\xd2\\x10\\x08\\n\\xcc\\xbe\\xa9\\xd0Ga\\xb5}\\xe5\\xcb;\\xad$|do\\xba\\xb5\\xed\\x9a<\\xbdO\\x83G\\xb9\\x95Bd\\xc8\\xc6\\xa8\\xd1?\\xff-\\xf1M\\x05\\x1c \\xd3\\n\\x96\\xb1\\xbe\\xdb\\xeb%/^b@\\x0fz\\xf9\\x864\\xc2ZR\\x89\\xff\\x9e\\x00?\\x12\\'O\\xf6\\x0c\\x8bO\\x06W\\x04\\xa7\\xc2\\x05g\\x89\\xbf3\\x9a9\\x9f\\'\\xee\\xb3\\x16>L\\xb0\\xf4\\xcd>\\xc7K\\xfc5\\xb1\\x85\\xec\\x99\\xd2\\x81\\xc3\\xc4\\xbd+\\xa5\\xc2\\xf5\\xf7k\\x1d\\x82\\xee?\\xff\\x98\\xf4\\xa3)>\\xc3\\xfa\\xeb\\x9b\\xe8\\xd40\\xdan8\\xe1\\x8f \\xd3\\x19\\xc4Gz\\xf8\\xe3\\x17\\xafm\\xfdd\\xb1\\x92\\x91`\\x1a\\xbe\\xd3\\x16\\xd4R\\x8e]\\xcf\\xea\\xac\\xb1\\xe7\\xd3z\\xcdw>\\x1c\\x1d\\x9dF\\xb3\\x1d\\xbe\\xf9\\xdf%\\x93\\x88\\xdf\\xf0\\x1c\\xc2\\xd2\\xdd\\xd7][\\x91d\\xdb\\xbc\\x96\\x19s\\x08\\xc5\\xba\\xb1A\\x06\\xea\\xe0\\x02\\x9dv%\\x9ed \\xe7\\xde\\xdfqU\\x05^gP\\xe0\\x8e\\xfd<i\\xdd\\x8f-\\xf9\\x17\\x07[\\x9a\"\\xcb{\\xe6\\xe7\\xaf'"
]
}
],
"prompt_number": 9
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# http://blog.oddbit.com/post/converting-openssh-public-keys\n",
"\n",
"import sys\n",
"import base64\n",
"import struct\n",
"\n",
"from pyasn1.type import univ\n",
"from pyasn1.codec.der import encoder as der_encoder\n",
"\n",
"# get the second field from the public key file.\n",
"keydata = base64.b64decode(\n",
" open(ID_RSA_PUB).read().split(None)[1])\n",
"\n",
"parts = []\n",
"while keydata:\n",
" # read the length of the data\n",
" dlen = struct.unpack('>I', keydata[:4])[0]\n",
"\n",
" # read in <length> bytes\n",
" data, keydata = keydata[4:dlen+4], keydata[4+dlen:]\n",
"\n",
" parts.append(data)\n",
" \n",
"e_val = eval('0x' + ''.join(['%02X' % struct.unpack('B', x)[0] for x in\n",
" parts[1]]))\n",
"n_val = eval('0x' + ''.join(['%02X' % struct.unpack('B', x)[0] for x in\n",
" parts[2]]))\n",
"\n",
"\n",
"\n",
"pkcs1_seq = univ.Sequence()\n",
"pkcs1_seq.setComponentByPosition(0, univ.Integer(n_val))\n",
"pkcs1_seq.setComponentByPosition(1, univ.Integer(e_val))\n",
"\n",
"\n",
"\n",
"print '-----BEGIN RSA PUBLIC KEY-----'\n",
"print base64.encodestring(der_encoder.encode(pkcs1_seq))\n",
"print '-----END RSA PUBLIC KEY-----'"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"-----BEGIN RSA PUBLIC KEY-----\n",
"MIIBCAKCAQEA7ozGYIwEEXj10hAICsy+qdBHYbV95cs7rSR8ZG+6te2aPL1Pg0e5lUJkyMao0T//\n",
"LfFNBRwg0wqWsb7b6yUvXmJAD3r5hjTCWlKJ/54APxInT/YMi08GVwSnwgVnib8zmjmfJ+6zFj5M\n",
"sPTNPsdL/DWxheyZ0oHDxL0rpcL192sdgu4//5j0oyk+w/rrm+jUMNpuOOGPINMZxEd6+OMXr239\n",
"ZLGSkWAavtMW1FKOXc/qrLHn03rNdz4cHZ1Gsx2++d8lk4jf8BzC0t3XXVuRZNu8lhlzCMW6sUEG\n",
"6uACnXYlnmQg597fcVUFXmdQ4I79PGndjy35FwdbmiLLe+bnrwIBIw==\n",
"\n",
"-----END RSA PUBLIC KEY-----\n"
]
}
],
"prompt_number": 10
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"n_val == key.key.n, e_val == key.key.e"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 11,
"text": [
"(True, True)"
]
}
],
"prompt_number": 11
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"import hashlib\n",
"m = hashlib.md5()\n",
"m.update(base64.encodestring(key.exportKey(format='DER')))\n",
"m.hexdigest()"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 21,
"text": [
"'bd3d18661b234de70ec52f8a1b558bdd'"
]
}
],
"prompt_number": 21
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"der_encoder.encode(pkcs1_seq, defMode=True)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 13,
"text": [
"'0\\x82\\x01\\x08\\x02\\x82\\x01\\x01\\x00\\xee\\x8c\\xc6`\\x8c\\x04\\x11x\\xf5\\xd2\\x10\\x08\\n\\xcc\\xbe\\xa9\\xd0Ga\\xb5}\\xe5\\xcb;\\xad$|do\\xba\\xb5\\xed\\x9a<\\xbdO\\x83G\\xb9\\x95Bd\\xc8\\xc6\\xa8\\xd1?\\xff-\\xf1M\\x05\\x1c \\xd3\\n\\x96\\xb1\\xbe\\xdb\\xeb%/^b@\\x0fz\\xf9\\x864\\xc2ZR\\x89\\xff\\x9e\\x00?\\x12\\'O\\xf6\\x0c\\x8bO\\x06W\\x04\\xa7\\xc2\\x05g\\x89\\xbf3\\x9a9\\x9f\\'\\xee\\xb3\\x16>L\\xb0\\xf4\\xcd>\\xc7K\\xfc5\\xb1\\x85\\xec\\x99\\xd2\\x81\\xc3\\xc4\\xbd+\\xa5\\xc2\\xf5\\xf7k\\x1d\\x82\\xee?\\xff\\x98\\xf4\\xa3)>\\xc3\\xfa\\xeb\\x9b\\xe8\\xd40\\xdan8\\xe1\\x8f \\xd3\\x19\\xc4Gz\\xf8\\xe3\\x17\\xafm\\xfdd\\xb1\\x92\\x91`\\x1a\\xbe\\xd3\\x16\\xd4R\\x8e]\\xcf\\xea\\xac\\xb1\\xe7\\xd3z\\xcdw>\\x1c\\x1d\\x9dF\\xb3\\x1d\\xbe\\xf9\\xdf%\\x93\\x88\\xdf\\xf0\\x1c\\xc2\\xd2\\xdd\\xd7][\\x91d\\xdb\\xbc\\x96\\x19s\\x08\\xc5\\xba\\xb1A\\x06\\xea\\xe0\\x02\\x9dv%\\x9ed \\xe7\\xde\\xdfqU\\x05^gP\\xe0\\x8e\\xfd<i\\xdd\\x8f-\\xf9\\x17\\x07[\\x9a\"\\xcb{\\xe6\\xe7\\xaf\\x02\\x01#'"
]
}
],
"prompt_number": 13
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"from paramiko import PKey"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 23
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"pk = PKey(data=key.exportKey('OpenSSH'))"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 25
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"!ssh-keygen -lf ~/.ssh/id_rsa.pub "
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"2048 89:33:28:02:e4:ef:c0:5e:f5:30:e1:4a:2c:1f:a3:b7 /Users/raymondyee/.ssh/id_rsa.pub (RSA)\r\n"
]
}
],
"prompt_number": 28
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"\":\".join([binascii.hexlify(x) for x in pk.get_fingerprint()]) "
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 27,
"text": [
"'d4:1d:8c:d9:8f:00:b2:04:e9:80:09:98:ec:f8:42:7e'"
]
}
],
"prompt_number": 27
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"#http://stackoverflow.com/a/14236337/7782\n",
"#!/usr/bin/python\n",
"\n",
"import binascii\n",
"import hashlib\n",
"\n",
"keyfile = ID_RSA_PUB\n",
"\n",
"def showHash(type, hash, data):\n",
" hash.update(data)\n",
" hex=hash.hexdigest()\n",
" hexbytes=[hex[i:i+2] for i in range(0, len(hex), 2)]\n",
" hexstring=\":\".join(hexbytes)\n",
" print type+\" \"+hexstring\n",
"\n",
"f = open(keyfile)\n",
"words = f.readline().split()\n",
"data=words[1]\n",
"\n",
"# binascii.a2b_base64(string)\n",
"# Convert a block of base64 data back to binary and return the binary data. More than one line may be passed at a time.\n",
"# http://docs.python.org/2/library/binascii.html\n",
"\n",
"bindata=binascii.a2b_base64(data)\n",
"\n",
"print data\n",
"\n",
"showHash(\"md5\", hashlib.md5(), bindata)\n",
"showHash(\"sha1\", hashlib.sha1(), bindata)\n",
"showHash(\"sha256\", hashlib.sha256(), bindata)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"AAAAB3NzaC1yc2EAAAABIwAAAQEA7ozGYIwEEXj10hAICsy+qdBHYbV95cs7rSR8ZG+6te2aPL1Pg0e5lUJkyMao0T//LfFNBRwg0wqWsb7b6yUvXmJAD3r5hjTCWlKJ/54APxInT/YMi08GVwSnwgVnib8zmjmfJ+6zFj5MsPTNPsdL/DWxheyZ0oHDxL0rpcL192sdgu4//5j0oyk+w/rrm+jUMNpuOOGPINMZxEd6+OMXr239ZLGSkWAavtMW1FKOXc/qrLHn03rNdz4cHZ1Gsx2++d8lk4jf8BzC0t3XXVuRZNu8lhlzCMW6sUEG6uACnXYlnmQg597fcVUFXmdQ4I79PGndjy35FwdbmiLLe+bnrw==\n",
"md5 89:33:28:02:e4:ef:c0:5e:f5:30:e1:4a:2c:1f:a3:b7\n",
"sha1 4b:14:fc:72:59:38:2c:0b:88:f4:12:23:b1:96:06:71:4b:68:3e:ea\n",
"sha256 d2:8a:f6:a7:b0:e9:6e:0e:e0:dd:70:f8:01:a3:52:a3:21:9a:df:b6:83:1c:26:cb:dd:78:7f:c0:1a:01:8a:66\n"
]
}
],
"prompt_number": 32
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {},
"outputs": []
}
],
"metadata": {}
}
]
}