Hi,
Here is a patch that adds the possibility of displaying key fingerprints
in the bubblebabble format used by ssh.com ssh implementations.
I hope it makes its way into the source.
--- ./openssh-2.5.1/key_original.h Sun Mar 4 00:47:55 2001
+++ ./openssh-2.5.1/key.h Sun Mar 4 00:57:57 2001
@@ -36,6 +36,17 @@
KEY_DSA,
KEY_UNSPEC
};
+
+enum digest_type {
+ DIGEST_TYPE_SHA1,
+ DIGEST_TYPE_MD5
+};
+
+enum digest_representation {
+ DIGEST_REPRESENTATION_HEX,
+ DIGEST_REPRESENTATION_BUBBLEBABBLE
+};
+
struct Key {
int type;
RSA *rsa;
@@ -46,6 +57,7 @@
Key *key_new_private(int type);
void key_free(Key *k);
int key_equal(Key *a, Key *b);
+char *key_fingerprint_ex(Key *k, enum digest_type dgst_type, enum
digest_representation dgst_representation);
char *key_fingerprint(Key *k);
char *key_type(Key *k);
int key_write(Key *key, FILE *f);
--- ./openssh-2.5.1/key_original.c Sun Mar 4 00:48:41 2001
+++ ./openssh-2.5.1/key.c Sun Mar 4 01:07:21 2001
@@ -153,6 +153,179 @@
return 0;
}
+u_char*
+key_fingerprint_raw(Key *k, enum digest_type dgst_type, size_t
*dgst_raw_length)
+{
+ u_char *blob = NULL;
+ u_char* retval = NULL;
+ int len = 0;
+ int nlen, elen;
+
+ switch (k->type) {
+ case KEY_RSA1:
+ nlen = BN_num_bytes(k->rsa->n);
+ elen = BN_num_bytes(k->rsa->e);
+ len = nlen + elen;
+ blob = xmalloc(len);
+ BN_bn2bin(k->rsa->n, blob);
+ BN_bn2bin(k->rsa->e, blob + nlen);
+ break;
+ case KEY_DSA:
+ case KEY_RSA:
+ key_to_blob(k, &blob, &len);
+ break;
+ case KEY_UNSPEC:
+ fatal("key_fingerprint_raw: bad key type
%d",k->type);
+ break;
+ default:
+ fatal("key_fingerprint_raw: bad key type %d",
k->type);
+ break;
+ }
+
+ if (blob != NULL) {
+ EVP_MD *md = NULL;
+ EVP_MD_CTX ctx;
+
+ retval = xmalloc(EVP_MAX_MD_SIZE);
+
+ switch (dgst_type) {
+ case DIGEST_TYPE_MD5:
+ md = EVP_md5();
+ break;
+ case DIGEST_TYPE_SHA1:
+ md = EVP_sha1();
+ break;
+ default:
+ fatal("key_fingerprint_raw: bad digest
type %d", dgst_type);
+ }
+
+ EVP_DigestInit(&ctx, md);
+ EVP_DigestUpdate(&ctx, blob, len);
+ EVP_DigestFinal(&ctx, retval, NULL);
+
+ *dgst_raw_length = md->md_size;
+
+ memset(blob, 0, len);
+ xfree(blob);
+ } else
+ fatal("key_fingerprint_raw: blob is null");
+
+ return retval;
+}
+
+char*
+key_fingerprint_hex(u_char* dgst_raw, size_t dgst_raw_len)
+{
+ char *retval;
+ int i;
+
+ retval = xmalloc(dgst_raw_len*3);
+
+ for(i = 0; i < dgst_raw_len; i++) {
+
+ char hex[4];
+
+ snprintf(hex, sizeof(hex), "%02x:", dgst_raw[i]);
+ strcat(retval, hex);
+ }
+
+ retval[(dgst_raw_len * 3) - 1] = '\0';
+ return retval;
+}
+
+char*
+key_fingerprint_bubblebabble(u_char* dgst_raw, size_t dgst_raw_len)
+{
+ char vowels[] = { 'a', 'e', 'i', 'o',
'u', 'y' };
+ char consonants[] = { 'b', 'c', 'd', 'f',
'g', 'h', 'k', 'l', 'm',
'n', 'p', 'r', 's', 't', 'v',
'z', 'x' };
+ unsigned int rounds, idx, retval_idx, seed;
+ char *retval;
+
+ rounds = (dgst_raw_len / 2) + 1;
+
+ retval = xmalloc(sizeof(char)*(rounds*6));
+
+ seed = 1;
+
+ retval_idx = 0;
+
+ retval[retval_idx++] = 'x';
+
+ for (idx=0;idx<rounds;idx++) {
+
+ unsigned int idx0, idx1, idx2, idx3, idx4;
+
+ if ((idx + 1 < rounds) || (dgst_raw_len % 2 != 0)) {
+
+ idx0 = (((((unsigned int)(dgst_raw[2*idx])) >> 6) & 3) + seed) %
6;
+ idx1 = (((unsigned int)(dgst_raw[2*idx])) >> 2) & 15;
+ idx2 = ((((unsigned int)(dgst_raw[2*idx])) & 3) + (seed / 6)) % 6;
+
+ retval[retval_idx++] = vowels[idx0];
+ retval[retval_idx++] = consonants[idx1];
+ retval[retval_idx++] = vowels[idx2];
+
+ if ((idx + 1) < rounds) {
+
+ idx3 = (((unsigned int)(dgst_raw[(2*idx) + 1])) >> 4) & 15;
+ idx4 = (((unsigned int)(dgst_raw[(2*idx) + 1]))) & 15;
+
+ retval[retval_idx++] = consonants[idx3];
+ retval[retval_idx++] = '-';
+ retval[retval_idx++] = consonants[idx4];
+
+ seed = ((seed * 5) + ((((unsigned int)(dgst_raw[2*idx])) * 7) +
((unsigned int)(dgst_raw[(2*idx) + 1])))) % 36;
+ }
+ } else {
+
+ idx0 = seed % 6;
+ idx1 = 16;
+ idx2 = seed / 6;
+
+ retval[retval_idx++] = vowels[idx0];
+ retval[retval_idx++] = consonants[idx1];
+ retval[retval_idx++] = vowels[idx2];
+
+ }
+ }
+
+ retval[retval_idx++] = 'x';
+ retval[retval_idx++] = '\0';
+
+ return retval;
+}
+
+char*
+key_fingerprint_ex(Key *k, enum digest_type dgst_type, enum
digest_representation dgst_representation)
+{
+ char *retval = NULL;
+ u_char *dgst_raw;
+ size_t dgst_raw_len;
+
+ dgst_raw = key_fingerprint_raw(k,dgst_type,&dgst_raw_len);
+
+ if (!dgst_raw)
+ fatal("key_fingerprint_ex: null value returned from
key_fingerprint_raw()");
+
+ switch(dgst_representation) {
+ case DIGEST_REPRESENTATION_HEX:
+ retval = key_fingerprint_hex(dgst_raw,dgst_raw_len);
+ break;
+
+ case DIGEST_REPRESENTATION_BUBBLEBABBLE:
+ retval = key_fingerprint_bubblebabble(dgst_raw,dgst_raw_len);
+ break;
+ default:
+ fatal("key_fingerprint_ex: bad digest representation
%d",dgst_representation);
+ break;
+ }
+
+ memset(dgst_raw, 0, dgst_raw_len);
+ xfree(dgst_raw);
+
+ return retval;
+}
+
/*
* Generate key fingerprint in ascii format.
* Based on ideas and code from Bjoern Groenvall <bg at sics.se>
--- ./openssh-2.5.1/ssh-keygen_original.c Sun Mar 4 00:49:31 2001
+++ ./openssh-2.5.1/ssh-keygen.c Sun Mar 4 00:52:56 2001
@@ -346,9 +346,22 @@
debug("try_load_public_key KEY_UNSPEC failed");
}
if (success) {
+
+ char *digest_sha1, *digest_bubblebabble;
+
+ digest_sha1
key_fingerprint_ex(public,DIGEST_TYPE_SHA1,DIGEST_REPRESENTATION_HEX);
+ digest_bubblebabble
key_fingerprint_ex(public,DIGEST_TYPE_SHA1,DIGEST_REPRESENTATION_BUBBLEBABBLE);
+
printf("%d %s %s\n", key_size(public), key_fingerprint(public),
comment);
+ printf("Alternative digests:\n");
+ printf(" sha1 : %s\n",digest_sha1);
+ printf(" bubblebabble : %s\n",digest_bubblebabble);
+
key_free(public);
xfree(comment);
+ xfree(digest_sha1);
+ xfree(digest_bubblebabble);
+
exit(0);
}
--
Carsten Raskgaard