├── LICENSE ├── README.md ├── breakdsa ├── brutedsa ├── keyr └── keyr.sql /LICENSE: -------------------------------------------------------------------------------- 1 | CC0 1.0 Universal 2 | 3 | Statement of Purpose 4 | 5 | The laws of most jurisdictions throughout the world automatically confer 6 | exclusive Copyright and Related Rights (defined below) upon the creator and 7 | subsequent owner(s) (each and all, an "owner") of an original work of 8 | authorship and/or a database (each, a "Work"). 9 | 10 | Certain owners wish to permanently relinquish those rights to a Work for the 11 | purpose of contributing to a commons of creative, cultural and scientific 12 | works ("Commons") that the public can reliably and without fear of later 13 | claims of infringement build upon, modify, incorporate in other works, reuse 14 | and redistribute as freely as possible in any form whatsoever and for any 15 | purposes, including without limitation commercial purposes. These owners may 16 | contribute to the Commons to promote the ideal of a free culture and the 17 | further production of creative, cultural and scientific works, or to gain 18 | reputation or greater distribution for their Work in part through the use and 19 | efforts of others. 20 | 21 | For these and/or other purposes and motivations, and without any expectation 22 | of additional consideration or compensation, the person associating CC0 with a 23 | Work (the "Affirmer"), to the extent that he or she is an owner of Copyright 24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work 25 | and publicly distribute the Work under its terms, with knowledge of his or her 26 | Copyright and Related Rights in the Work and the meaning and intended legal 27 | effect of CC0 on those rights. 28 | 29 | 1. Copyright and Related Rights. A Work made available under CC0 may be 30 | protected by copyright and related or neighboring rights ("Copyright and 31 | Related Rights"). Copyright and Related Rights include, but are not limited 32 | to, the following: 33 | 34 | i. the right to reproduce, adapt, distribute, perform, display, communicate, 35 | and translate a Work; 36 | 37 | ii. moral rights retained by the original author(s) and/or performer(s); 38 | 39 | iii. publicity and privacy rights pertaining to a person's image or likeness 40 | depicted in a Work; 41 | 42 | iv. rights protecting against unfair competition in regards to a Work, 43 | subject to the limitations in paragraph 4(a), below; 44 | 45 | v. rights protecting the extraction, dissemination, use and reuse of data in 46 | a Work; 47 | 48 | vi. database rights (such as those arising under Directive 96/9/EC of the 49 | European Parliament and of the Council of 11 March 1996 on the legal 50 | protection of databases, and under any national implementation thereof, 51 | including any amended or successor version of such directive); and 52 | 53 | vii. other similar, equivalent or corresponding rights throughout the world 54 | based on applicable law or treaty, and any national implementations thereof. 55 | 56 | 2. Waiver. To the greatest extent permitted by, but not in contravention of, 57 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and 58 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright 59 | and Related Rights and associated claims and causes of action, whether now 60 | known or unknown (including existing as well as future claims and causes of 61 | action), in the Work (i) in all territories worldwide, (ii) for the maximum 62 | duration provided by applicable law or treaty (including future time 63 | extensions), (iii) in any current or future medium and for any number of 64 | copies, and (iv) for any purpose whatsoever, including without limitation 65 | commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes 66 | the Waiver for the benefit of each member of the public at large and to the 67 | detriment of Affirmer's heirs and successors, fully intending that such Waiver 68 | shall not be subject to revocation, rescission, cancellation, termination, or 69 | any other legal or equitable action to disrupt the quiet enjoyment of the Work 70 | by the public as contemplated by Affirmer's express Statement of Purpose. 71 | 72 | 3. Public License Fallback. Should any part of the Waiver for any reason be 73 | judged legally invalid or ineffective under applicable law, then the Waiver 74 | shall be preserved to the maximum extent permitted taking into account 75 | Affirmer's express Statement of Purpose. In addition, to the extent the Waiver 76 | is so judged Affirmer hereby grants to each affected person a royalty-free, 77 | non transferable, non sublicensable, non exclusive, irrevocable and 78 | unconditional license to exercise Affirmer's Copyright and Related Rights in 79 | the Work (i) in all territories worldwide, (ii) for the maximum duration 80 | provided by applicable law or treaty (including future time extensions), (iii) 81 | in any current or future medium and for any number of copies, and (iv) for any 82 | purpose whatsoever, including without limitation commercial, advertising or 83 | promotional purposes (the "License"). The License shall be deemed effective as 84 | of the date CC0 was applied by Affirmer to the Work. Should any part of the 85 | License for any reason be judged legally invalid or ineffective under 86 | applicable law, such partial invalidity or ineffectiveness shall not 87 | invalidate the remainder of the License, and in such case Affirmer hereby 88 | affirms that he or she will not (i) exercise any of his or her remaining 89 | Copyright and Related Rights in the Work or (ii) assert any associated claims 90 | and causes of action with respect to the Work, in either case contrary to 91 | Affirmer's express Statement of Purpose. 92 | 93 | 4. Limitations and Disclaimers. 94 | 95 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 96 | surrendered, licensed or otherwise affected by this document. 97 | 98 | b. Affirmer offers the Work as-is and makes no representations or warranties 99 | of any kind concerning the Work, express, implied, statutory or otherwise, 100 | including without limitation warranties of title, merchantability, fitness 101 | for a particular purpose, non infringement, or the absence of latent or 102 | other defects, accuracy, or the present or absence of errors, whether or not 103 | discoverable, all to the greatest extent permissible under applicable law. 104 | 105 | c. Affirmer disclaims responsibility for clearing rights of other persons 106 | that may apply to the Work or any use thereof, including without limitation 107 | any person's Copyright and Related Rights in the Work. Further, Affirmer 108 | disclaims responsibility for obtaining any necessary consents, permissions 109 | or other rights required for any use of the Work. 110 | 111 | d. Affirmer understands and acknowledges that Creative Commons is not a 112 | party to this document and has no duty or obligation with respect to this 113 | CC0 or use of the Work. 114 | 115 | For more information, please see 116 | 117 | 118 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Scripts to analyze the PGP key server data 2 | ========================================== 3 | 4 | background 5 | ---------- 6 | 7 | * [A look at the PGP ecosystem through the key server data (background paper)](http://eprint.iacr.org/2015/262) 8 | * [Slides from talk at BSidesHN](http://int21.de/slides/slides-pgp.pdf) 9 | 10 | keyr 11 | ---- 12 | 13 | keyr will take concatenated PGP keys like the ones provided by key server 14 | dumps as the input and will output mysql queries. 15 | 16 | Usage: 17 | 18 | `keyr [filename]` 19 | 20 | The corresponding sql tables are in the file keyr.sql. 21 | 22 | breakdsa 23 | -------- 24 | 25 | Breaks DSA keys when two signatures with a duplicate k / r value are found. 26 | 27 | Usage: 28 | 29 | `breakdsa [filename]` 30 | 31 | The script expects a 12-column input file (tab separated) with the following values: 32 | 33 | * col 1: Key ID of affected DSA key (only used for output info) 34 | * col 2: r value (same for both signatures) 35 | * col 3: s value of first signature 36 | * col 4: s value of second signature 37 | * col 5: hash value of first signature 38 | * col 6: hash value of second signature 39 | * col 7: p value of DSA key 40 | * col 8: q value of DSA key 41 | * col 9: g value of DSA key 42 | * col 10: y value of DSA key 43 | 44 | All values are expected hex encoded. 45 | 46 | The MySQL query to get the data pre-formatted to feed into this script is: 47 | 48 | `SELECT a.keyid, a.dsa_r, a.dsa_s, b.dsa_s, a.hash, b.hash, c.dsa_p, c.dsa_q, c.dsa_g, c.dsa_y FROM sigs_dsa a JOIN sigs_dsa b JOIN keys_dsa c ON a.dsa_r = b.dsa_r AND a.dsa_s <> b.dsa_s AND a.keyid = c.keyid GROUP BY a.dsa_r INTO OUTFILE '/tmp/dsa-duplicate-r.txt';` 49 | 50 | brutedsa 51 | -------- 52 | 53 | Brute forces DSA keys for occurences of small k values. 54 | 55 | Usage: 56 | 57 | `brutedsa [filename]` 58 | 59 | The script expects a 12-column input file (tab separated) with the following values: 60 | 61 | * col 1: Key ID of affected DSA key (only used for output info) 62 | * col 2: r value of signature 63 | * col 3: s value of signature 64 | * col 4: hash of signature 65 | * col 5: p value of key 66 | * col 6: q value of key 67 | * col 7: g value of key 68 | * col 8: y value of key 69 | 70 | All values are expected hex encoded. 71 | 72 | The MySQL query to get the data pre-formatted to feed into this script is: 73 | 74 | `SELECT A.id,A.keyid,A.dsa_r,A.dsa_s,hash,dsa_p,dsa_q,dsa_g,dsa_y FROM sigs_dsa A LEFT JOIN keys_dsa B ON A.keyid = B.keyid INTO OUTFILE '/tmp/dsa-sigs-with-keys.txt';` 75 | 76 | links 77 | ----- 78 | 79 | * [Key server dumps](https://bitbucket.org/skskeyserver/sks-keyserver/wiki/KeydumpSources) 80 | * [RFC 4880 (OpenPGP packet format)](https://tools.ietf.org/html/rfc4880) 81 | * [PGP archive including source code](ftp://ftp.pgpi.org/pub/pgp) 82 | * [Evil 32 - info about short PGP key ids](https://evil32.com/) 83 | -------------------------------------------------------------------------------- /breakdsa: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | helptext = """ 4 | Breaks DSA keys when two signatures with a duplicate k / r value are found. 5 | 6 | Usage: 7 | breakdsa [filename] 8 | 9 | The script expects a 12-column input file (tab separated) with the following values: 10 | col 1: Key ID of affected DSA key (only used for output info) 11 | col 2: r value (same for both signatures) 12 | col 3: s value of first signature 13 | col 4: s value of second signature 14 | col 5: hash value of first signature 15 | col 6: hash value of second signature 16 | col 7: p value of DSA key 17 | col 8: q value of DSA key 18 | col 9: g value of DSA key 19 | col 10: y value of DSA key 20 | 21 | All values are expected hex encoded. 22 | 23 | The MySQL query to get the data pre-formatted to feed into this script is: 24 | 25 | SELECT a.keyid, a.dsa_r, a.dsa_s, b.dsa_s, a.hash, b.hash, c.dsa_p, c.dsa_q, c.dsa_g, c.dsa_y FROM sigs_dsa a JOIN sigs_dsa b JOIN keys_dsa c ON a.dsa_r = b.dsa_r AND a.dsa_s <> b.dsa_s AND a.keyid = c.keyid GROUP BY a.dsa_r INTO OUTFILE '/tmp/dsa-duplicate-r.txt'; 26 | """ 27 | 28 | import gmpy2, sys 29 | 30 | def breakdsa(keyid, r, s1, s2, h1, h2, p, q, g, y): 31 | try: 32 | down = gmpy2.invert((s1-s2), q) 33 | up = gmpy2.t_mod(h1-h2, q) 34 | 35 | mul = gmpy2.mul(down, up) 36 | k = gmpy2.t_mod(mul, q) 37 | 38 | r_inv = gmpy2.invert(r, q) 39 | 40 | x1 = gmpy2.t_mod((s1*k-h1)*r_inv, q) 41 | x2 = gmpy2.t_mod((s2*k-h2)*r_inv, q) 42 | if x1 < 0: x1 += q 43 | if x2 < 0: x2 += q 44 | 45 | y1 = gmpy2.powmod(g, x1, p) 46 | y2 = gmpy2.powmod(g, x2, p) 47 | 48 | # when both back-calculated y-values match and both x-values identical we likely broke a key 49 | if (y1 == y2) and (y1 == y): 50 | print("We found a breakable key") 51 | print("y: %s"% hex(y)) 52 | print("k: %s" % hex(k)) 53 | print("r: %s" % hex(r)) 54 | print("keyid: %s" % hex(keyid)) 55 | if x1 == x2: 56 | print("x: %s (private key)"% hex(x1)) 57 | else: 58 | print("y match, but no x match") 59 | print("x1: %s (private key)"% hex(x1)) 60 | print("x2: %s (private key)"% hex(x2)) 61 | print("") 62 | 63 | except ZeroDivisionError: 64 | pass 65 | 66 | if len(sys.argv) != 2: 67 | print(helptext) 68 | sys.exit(1) 69 | 70 | with open(sys.argv[1]) as fp: 71 | for line in fp: 72 | x = line.split() 73 | if (len(x) == 10) and (x[4] != "none") and (x[5] != "none"): 74 | for i in range(10): 75 | x[i] = gmpy2.mpz(x[i], 16) 76 | breakdsa(x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9]) 77 | -------------------------------------------------------------------------------- /brutedsa: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | helptext = """ 4 | Brute forces DSA keys for occurences of small k values. 5 | 6 | Usage: 7 | brutedsa [filename] 8 | 9 | The script expects a 12-column input file (tab separated) with the following values: 10 | col 1: Key ID of affected DSA key (only used for output info) 11 | col 2: r value of signature 12 | col 3: s value of signature 13 | col 4: hash of signature 14 | col 5: p value of key 15 | col 6: q value of key 16 | col 7: g value of key 17 | col 8: y value of key 18 | 19 | All values are expected hex encoded. 20 | 21 | The MySQL query to get the data pre-formatted to feed into this script is: 22 | 23 | SELECT A.id,A.keyid,A.dsa_r,A.dsa_s,hash,dsa_p,dsa_q,dsa_g,dsa_y FROM sigs_dsa A LEFT JOIN keys_dsa B ON A.keyid = B.keyid INTO OUTFILE '/tmp/dsa-sigs-with-keys.txt'; 24 | """ 25 | 26 | import gmpy2, sys 27 | 28 | try_k = list(range(0, 100)) 29 | 30 | def brutedsa(sigid, keyid, r, s, h, p, q, g, y): 31 | 32 | r_inv = gmpy2.invert(r, q) 33 | 34 | for k in try_k: 35 | x = gmpy2.t_mod((s*k-h)*r_inv, q) 36 | if x < 0: x += q 37 | y1 = gmpy2.powmod(g, x, p) 38 | if y1 == y: 39 | print("") 40 | print("found suspicious sig %s" % sigid) 41 | print("k: %s" % k) 42 | print("x: %s" % x) 43 | 44 | if len(sys.argv) != 2: 45 | print(helptext) 46 | sys.exit(1) 47 | 48 | with open(sys.argv[1]) as fp: 49 | i = 0 50 | for line in fp: 51 | i += 1 52 | if (i % 1000) == 0: sys.stdout.write('.') 53 | x = line.split("\t") 54 | try: 55 | brutedsa(x[0], x[1], gmpy2.mpz(x[2], 16), gmpy2.mpz(x[3], 16), gmpy2.mpz(x[4], 16), gmpy2.mpz(x[5], 16), gmpy2.mpz(x[6], 16), gmpy2.mpz(x[7], 16), gmpy2.mpz(x[8], 16)) 56 | except ValueError: 57 | pass 58 | -------------------------------------------------------------------------------- /keyr: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | # PGP packet format RFC 4880 4 | # https://tools.ietf.org/html/rfc4880 5 | # keyserver dumps 6 | # https://bitbucket.org/skskeyserver/sks-keyserver/wiki/KeydumpSources 7 | 8 | import argparse 9 | import struct 10 | import binascii 11 | import hashlib 12 | import sys 13 | import gmpy2 14 | 15 | 16 | def DEBUG(s): 17 | # print(s) 18 | pass 19 | 20 | 21 | smallprimes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021] 22 | primeprod = 1 23 | for prime in smallprimes: 24 | primeprod *= prime 25 | DEBUG("Small prime product %i" % primeprod) 26 | 27 | 28 | pkalg_table = {1: "RSA(ES)", 29 | 2: "RSA(E)", 30 | 3: "RSA(S)", 31 | 16: "ElG(E)", 32 | 17: "DSA", 33 | 18: "ECC", 34 | 19: "ECDSA", 35 | 20: "ElG(ES)", 36 | 21: "DH"} 37 | 38 | hashalg_table = {1: "MD5", 39 | 2: "SHA1", 40 | 3: "RIPEMD160", 41 | 8: "SHA256", 42 | 9: "SHA384", 43 | 10: "SHA512", 44 | 11: "SHA224"} 45 | 46 | curve_table = {b'\x2a\x86\x48\xce\x3d\x03\x01\x07': 'nistp256', 47 | b'\x2b\x81\x04\x00\x22': 'nistp384', 48 | b'\x2b\x81\x04\x00\x23': 'nistp521', 49 | b'\x2b\x81\x04\x00\x0a': 'nistk256', 50 | b'\x2b\x24\x03\x03\x02\x08\x01\x01\x07': 'brainpoolp256', 51 | b'\x2b\x24\x03\x03\x02\x08\x01\x01\x0b': 'brainpoolp384', 52 | b'\x2b\x24\x03\x03\x02\x08\x01\x01\x0d': 'brainpoolp512', 53 | b'\x2b\x06\x01\x04\x01\xda\x47\x0f\x00': 'curve25519'} 54 | 55 | 56 | def sigtype(i): 57 | if i == 0x00: return "bindoc" 58 | elif i == 0x01: return "text" 59 | elif i == 0x02: return "standalone" 60 | elif i == 0x10: return "gencert" 61 | elif i == 0x11: return "perscert" 62 | elif i == 0x12: return "casualcert" 63 | elif i == 0x13: return "positivecert" 64 | elif i == 0x18: return "subkey_binding" 65 | elif i == 0x19: return "primkey_binding" 66 | elif i == 0x1f: return "direct_key" 67 | elif i == 0x20: return "revocation" 68 | elif i == 0x28: return "subkey_revocation" 69 | elif i == 0x30: return "cert_revocation" 70 | elif i == 0x40: return "timestamp" 71 | elif i == 0x50: return "thirdparty_confirmation" 72 | else: return "Unk %x" % i 73 | 74 | 75 | def mpi_read(f): 76 | len = int((struct.unpack(">H", f.read(2))[0] + 7)) >> 3 77 | return binascii.hexlify(f.read(len)).decode('ascii') 78 | 79 | 80 | def pgp_parse(filename, mode, PRIMECHECK): 81 | f = open(filename, 'rb') 82 | 83 | packet_next = 0 84 | 85 | last_subkey_size = 0 86 | last_subkey_realstart = 0 87 | 88 | dsa_p_prime = True 89 | dsa_q_prime = True 90 | rsa_smallfact = False 91 | 92 | while 1: 93 | f.seek(packet_next) 94 | packet_start = packet_next 95 | 96 | packet_sig = f.read(1) 97 | if len(packet_sig) == 0: 98 | break # end of file 99 | packet_sig = struct.unpack("B", packet_sig)[0] 100 | 101 | if (packet_sig & (1 << 7)) != 0: 102 | DEBUG("") 103 | DEBUG("*packet*") 104 | else: 105 | print("wrong packet at offset %i" % packet_start) 106 | break 107 | 108 | if (packet_sig & (1 << 6)) != 0: # Bit 6 109 | packet_format = "new" 110 | packet_tag = packet_sig & 0x3f # Bit 5-0 111 | 112 | packet_size = struct.unpack("B", f.read(1))[0] 113 | if packet_size == 255: 114 | packet_size = struct.unpack(">L", f.read(4))[0] 115 | elif packet_size >= 192: 116 | packet_size = ((packet_size - 192) << 8) + 192 + struct.unpack("B", f.read(1))[0] 117 | else: 118 | packet_format = "old" 119 | packet_tag = (packet_sig >> 2) & 0xf # Bit 5-2 120 | packet_lengthtype = packet_sig & 0x3 # Bit 0-1 121 | if packet_lengthtype == 0: packet_size = struct.unpack("B", f.read(1))[0] 122 | elif packet_lengthtype == 1: packet_size = struct.unpack(">H", f.read(2))[0] 123 | elif packet_lengthtype == 2: packet_size = struct.unpack(">L", f.read(4))[0] 124 | else: 125 | DEBUG("Strange packet lengthtype %i" % packet_lengthtype) # this should go to stderr 126 | break 127 | 128 | packet_realstart = f.tell() 129 | packet_next = packet_realstart + packet_size 130 | DEBUG("packet_realstart %i" % packet_realstart) 131 | 132 | DEBUG("sig %x format %s tag %i size 0x%x %i" % (packet_sig, packet_format, packet_tag, packet_size, packet_size)) 133 | 134 | if packet_tag == 6: # Public Key 135 | key_start = last_pubkey_start = packet_start 136 | key_realstart = last_pubkey_realstart = packet_realstart 137 | key_size = last_pubkey_size = packet_size 138 | DEBUG("found pubkey start %i realstart %i size %i" % (last_pubkey_start, last_pubkey_realstart, last_pubkey_size)) 139 | key_sub = 0 140 | 141 | if packet_tag == 14: # Public Key 142 | key_start = last_subkey_start = packet_start 143 | key_realstart = last_subkey_realstart = packet_realstart 144 | key_size = last_subkey_size = packet_size 145 | DEBUG("found subkey start %i realstart %i size %i" % (last_subkey_start, last_subkey_realstart, last_subkey_size)) 146 | key_sub = 1 147 | 148 | if packet_tag in [6, 14]: # key 149 | key_ver = struct.unpack("B", f.read(1))[0] 150 | if key_ver in [2, 3]: 151 | DEBUG("v23 key found") 152 | key_time = struct.unpack(">L", f.read(4))[0] 153 | f.seek(f.tell() + 2) 154 | key_pkalg = struct.unpack("B", f.read(1))[0] 155 | key_pkalgd = pkalg_table.get(key_pkalg, "Unk %i" % key_pkalg) 156 | elif key_ver == 4: 157 | DEBUG("v4 key found") 158 | key_time = struct.unpack(">L", f.read(4))[0] 159 | key_pkalg = struct.unpack("B", f.read(1))[0] 160 | key_pkalgd = pkalg_table.get(key_pkalg, "Unk %i" % key_pkalg) 161 | else: 162 | DEBUG("unknown key ver") 163 | key_pkalg = 0 164 | key_pkalgd = "" 165 | DEBUG("pkalg %i %s" % (key_pkalg, key_pkalgd)) 166 | 167 | if key_pkalgd == "DSA": 168 | dsa_p = mpi_read(f) 169 | dsa_bits = len(dsa_p) * 4 170 | dsa_q = mpi_read(f) 171 | if PRIMECHECK: 172 | dsa_p_prime = gmpy2.is_prime(gmpy2.mpz(dsa_p, 16)) 173 | dsa_q_prime = gmpy2.is_prime(gmpy2.mpz(dsa_q, 16)) 174 | dsa_g = mpi_read(f) 175 | dsa_y = mpi_read(f) 176 | key_alg = "DSA" 177 | DEBUG("dsa_p %s" % dsa_p) 178 | DEBUG("dsa_q %s" % dsa_q) 179 | DEBUG("dsa_g %s" % dsa_g) 180 | DEBUG("dsa_y %s" % dsa_y) 181 | elif key_pkalgd[0:3] == "ElG": 182 | dsa_p = mpi_read(f) 183 | dsa_bits = len(dsa_p) * 4 184 | if PRIMECHECK: 185 | dsa_p_prime = gmpy2.is_prime(gmpy2.mpz(dsa_p, 16)) 186 | dsa_q_prime = True 187 | dsa_g = mpi_read(f) 188 | dsa_y = mpi_read(f) 189 | dsa_q = "" 190 | key_alg = "ElGamal" 191 | elif key_pkalgd[0:3] == "RSA": 192 | rsa_n = mpi_read(f) 193 | rsa_bits = len(rsa_n) * 4 194 | rsa_e = mpi_read(f) 195 | a, b = gmpy2.f_divmod(gmpy2.mpz(rsa_n, 16), primeprod) 196 | if b == 0: 197 | DEBUG("RSA with small factor") 198 | rsa_smallfact = True 199 | else: 200 | rsa_smallfact = False 201 | DEBUG("rsa_n %s" % rsa_n) 202 | DEBUG("rsa_e %s" % rsa_e) 203 | DEBUG("rsa_bits %s" % rsa_bits) 204 | elif (key_pkalgd == "ECDSA") or (key_pkalgd == "ECC"): 205 | key_alg = key_pkalgd 206 | curvelen = struct.unpack("B", f.read(1))[0] 207 | curveraw = f.read(curvelen) 208 | curve_type = curve_table.get(curveraw, 'unknown') 209 | DEBUG("curve %s" % curve_type) 210 | curve_point = mpi_read(f) 211 | else: 212 | sys.stderr.write("Unknown PK algorithm %s at %i\n" % (key_pkalgd, packet_start)) 213 | 214 | key_id = "" 215 | if key_pkalgd[0:3] == "RSA" and key_ver in [2, 3]: 216 | key_id = rsa_n[-16:] 217 | if key_ver == 4: 218 | keyhash = hashlib.sha1() 219 | keyhash.update(b'\x99') 220 | keyhash.update(struct.pack(">H", key_size)) 221 | f.seek(key_realstart) 222 | keyhash.update(f.read(key_size)) 223 | key_id = keyhash.hexdigest()[-16:] 224 | 225 | if key_sub == 0: last_pubkey_id = key_id 226 | key_id_short = key_id[-8:] 227 | DEBUG("keyid %s %s" % (key_id_short, key_id)) 228 | 229 | if mode == 'sql': 230 | if key_pkalgd == "DSA" or key_pkalgd[0:3] == "ElG": 231 | 232 | if (not dsa_p_prime) and (not dsa_q_prime): 233 | dsa_err = "('p_notprime,q_notprime')" 234 | elif not dsa_q_prime: 235 | dsa_err = "('q_notprime')" 236 | elif not dsa_p_prime: 237 | dsa_err = "('p_notprime')" 238 | else: 239 | dsa_err = "('')" 240 | 241 | print("INSERT INTO keys_dsa (keyid, keyid_short, keyid_master, alg, dsa_p, dsa_q, dsa_g, dsa_y, dsa_bits, ver, sub, errors, file, keyoffset, masteroffset) VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %i, %i, %s, '%s', %i, %i);" % (key_id, key_id_short, last_pubkey_id, key_alg, dsa_p, dsa_q, dsa_g, dsa_y, dsa_bits, key_ver, key_sub, dsa_err, filename, key_start, last_pubkey_start)) 242 | elif key_pkalgd[0:3] == "RSA": 243 | rsa_err = "" 244 | if rsa_smallfact: rsa_err = "smallfact" 245 | 246 | print("INSERT INTO keys_rsa (keyid, keyid_short, keyid_master, rsa_n, rsa_e, rsa_bits, ver, sub, errors, file, keyoffset, masteroffset) VALUES ('%s', '%s', '%s', '%s', '%s','%s', %i, %i, '%s', '%s', %i, %i);" % (key_id, key_id_short, last_pubkey_id, rsa_n, rsa_e, rsa_bits, key_ver, key_sub, rsa_err, filename, key_start, last_pubkey_start)) 247 | elif key_pkalgd == "ECC" or key_pkalgd == "ECDSA": 248 | 249 | print("INSERT INTO keys_ecc (keyid, keyid_short, keyid_master, alg, curve_type, curve_point, ver, sub, file, keyoffset, masteroffset) VALUES ('%s', '%s', '%s', '%s', '%s', '%s', %i, %i, '%s', %i, %i);" % (key_id, key_id_short, last_pubkey_id, key_alg, curve_type, curve_point, key_ver, key_sub, filename, key_start, last_pubkey_start)) 250 | 251 | elif mode == 'check': 252 | if key_pkalgd == "DSA": 253 | if not dsa_p_prime: print("WARNING! DSA p of key %s (subkey of %s) not prime" % (key_id, last_pubkey_id)) 254 | if not dsa_q_prime: print("WARNING! DSA q of key %s (subkey of %s) not prime" % (key_id, last_pubkey_id)) 255 | elif key_pkalgd == "Elg": 256 | if not dsa_p_prime: print("WARNING! ElGamal p of key %s (subkey of %s) not prime" % (key_id, last_pubkey_id)) 257 | 258 | if packet_tag == 13: # UID 259 | last_uid_start = packet_start 260 | last_uid_realstart = packet_realstart 261 | last_uid_size = packet_size 262 | DEBUG("found uid start %i realstart %i size %i" % (last_uid_start, last_uid_realstart, last_uid_size)) 263 | 264 | if packet_tag == 2: # Signature Packet 265 | 266 | DEBUG("signature found") 267 | sig_version = struct.unpack("B", f.read(1))[0] 268 | 269 | if (sig_version != 0x03) and (sig_version != 0x04) and (sig_version != 0x02): 270 | sys.stderr.write("ERROR: Sig not v3 or v4 %i\n" % sig_version) 271 | continue 272 | 273 | sig_pkalg = 0 274 | sig_pkalgd = "" 275 | sig_hash_str = "" 276 | 277 | if sig_version == 0x03: 278 | DEBUG("sig v3 found") 279 | if struct.unpack("B", f.read(1))[0] != 5: 280 | DEBUG("invalid v3 length field") 281 | sig_type = struct.unpack("B", f.read(1))[0] 282 | DEBUG("sig: %x %s" % (sig_type, sigtype(sig_type))) 283 | 284 | sig_issuer_time = f.read(4) 285 | sig_issuer_keyid = binascii.hexlify(f.read(8)).decode('ascii') 286 | sig_pkalg = struct.unpack("B", f.read(1))[0] 287 | sig_hashalg = struct.unpack("B", f.read(1))[0] 288 | sig_pkalgd = pkalg_table.get(sig_pkalg, "Unk %i" % sig_pkalg) 289 | sig_hashalgd = hashalg_table.get(sig_hashalg, "Unk %i" % sig_hashalg) 290 | DEBUG("pkalg %s 0x%x hashalg %s 0x%x" % (sig_pkalgd, sig_pkalg, sig_hashalgd, sig_hashalg)) 291 | sig_hash_upper_16bits = binascii.hexlify(f.read(2)).decode('ascii') 292 | DEBUG("hash left bits %s" % sig_hash_upper_16bits) 293 | if sig_pkalgd == "DSA": 294 | sig_r_length = int((struct.unpack(">H", f.read(2))[0] + 7) / 8) 295 | sig_r = binascii.hexlify(f.read(sig_r_length)).decode('ascii') 296 | sig_s_length = int((struct.unpack(">H", f.read(2))[0] + 7) / 8) 297 | sig_s = binascii.hexlify(f.read(sig_r_length)).decode('ascii') 298 | DEBUG("r: %s" % sig_r) 299 | DEBUG("s: %s" % sig_s) 300 | elif sig_pkalgd[0:3] == "RSA": 301 | sig_rsa_length = int((struct.unpack(">H", f.read(2))[0] + 7) / 8) 302 | sig_rsa = binascii.hexlify(f.read(sig_rsa_length)).decode('ascii') 303 | 304 | if sig_version == 0x04: 305 | DEBUG("signature v4 found") 306 | sig_type = struct.unpack("B", f.read(1))[0] 307 | DEBUG("sig: %x %s" % (sig_type, sigtype(sig_type))) 308 | 309 | sig_pkalg = struct.unpack("B", f.read(1))[0] 310 | 311 | sig_hashalg = struct.unpack("B", f.read(1))[0] 312 | 313 | sig_pkalgd = pkalg_table.get(sig_pkalg, "Unk %i" % sig_pkalg) 314 | 315 | sig_hashalgd = hashalg_table.get(sig_hashalg, "Unk %i" % sig_hashalg) 316 | 317 | DEBUG("pkalg %s 0x%x hashalg %s 0x%x" % (sig_pkalgd, sig_pkalg, sig_hashalgd, sig_hashalg)) 318 | 319 | sig_count_hashed_subpackets = struct.unpack(">H", f.read(2))[0] 320 | sig_offset_hashed_subpackets = f.tell() 321 | DEBUG("hashed subpackets %i" % sig_count_hashed_subpackets) 322 | f.seek(f.tell() + sig_count_hashed_subpackets) 323 | sig_end_hashed_subpackets = f.tell() 324 | DEBUG("packet_realstart %i sig_end_hashed_subpackets %i" % (packet_realstart, sig_end_hashed_subpackets)) 325 | 326 | sig_count_unhashed_subpackets = struct.unpack(">H", f.read(2))[0] 327 | sig_offset_unhashed_subpackets = f.tell() 328 | DEBUG("unhashed subpackets %i" % sig_count_unhashed_subpackets) 329 | 330 | sig_issuer_keyid = "" 331 | while f.tell() < (sig_offset_unhashed_subpackets + sig_count_unhashed_subpackets): 332 | subpacket_len = struct.unpack("B", f.read(1))[0] 333 | if subpacket_len == 255: 334 | subpacket_len = struct.unpack(">L", f.read(4))[0] 335 | elif subpacket_len >= 192: 336 | subpacket_len = ((subpacket_len - 192) << 8) + 192 + struct.unpack("B", f.read(1))[0] 337 | DEBUG("subpacket_len %i" % subpacket_len) 338 | subpacket_type = struct.unpack("B", f.read(1))[0] 339 | if subpacket_type == 16: # issuer keyid 340 | sig_issuer_keyid = binascii.hexlify(f.read(subpacket_len - 1)).decode('ascii') 341 | if len(sig_issuer_keyid) > 16: 342 | sig_issuer_keyid = sig_issuer_keyid[0:14] + ".." 343 | DEBUG("issuer keyid %s" % sig_issuer_keyid) 344 | 345 | f.seek(sig_offset_unhashed_subpackets + sig_count_unhashed_subpackets) 346 | 347 | sig_hash_upper_16bits = binascii.hexlify(f.read(2)).decode('ascii') 348 | DEBUG("hash upper 16 bits %s" % sig_hash_upper_16bits) 349 | sig_data_offset = f.tell() 350 | 351 | if sig_type in [0x10, 0x11, 0x12, 0x13] and (sig_hashalgd[0:3] != "Unk"): 352 | sig_hash = hashlib.new(sig_hashalgd) 353 | sig_hash.update(b'\x99') 354 | sig_hash.update(struct.pack(">H", last_pubkey_size)) 355 | f.seek(last_pubkey_realstart) 356 | sig_hash.update(f.read(last_pubkey_size)) 357 | sig_hash.update(b'\xb4') 358 | sig_hash.update(struct.pack(">L", last_uid_size)) 359 | f.seek(last_uid_realstart) 360 | sig_hash.update(f.read(last_uid_size)) 361 | 362 | f.seek(packet_realstart) 363 | sig_hash.update(f.read(sig_end_hashed_subpackets - packet_realstart)) 364 | 365 | sig_hash.update(b'\x04\xff') 366 | sig_hash.update(struct.pack(">L", sig_end_hashed_subpackets - packet_realstart)) 367 | sig_hash_str = sig_hash.hexdigest() 368 | 369 | elif sig_type in [0x18] and (sig_hashalgd[0:3] != "Unk"): 370 | sig_hash = hashlib.new(sig_hashalgd) 371 | sig_hash.update(b'\x99') 372 | sig_hash.update(struct.pack(">H", last_pubkey_size)) 373 | f.seek(last_pubkey_realstart) 374 | sig_hash.update(f.read(last_pubkey_size)) 375 | sig_hash.update(b'\x99') 376 | sig_hash.update(struct.pack(">H", last_subkey_size)) 377 | f.seek(last_subkey_realstart) 378 | sig_hash.update(f.read(last_subkey_size)) 379 | 380 | f.seek(packet_realstart) 381 | sig_hash.update(f.read(sig_end_hashed_subpackets - packet_realstart)) 382 | 383 | sig_hash.update(b'\x04\xff') 384 | sig_hash.update(struct.pack(">L", sig_end_hashed_subpackets - packet_realstart)) 385 | sig_hash_str = sig_hash.hexdigest() 386 | 387 | else: 388 | sig_hash_str = "none" 389 | 390 | DEBUG("hash: %s" % sig_hash_str) 391 | if sig_hash_upper_16bits == sig_hash_str[0:4]: 392 | DEBUG("good hash") 393 | hash_good = "1" 394 | else: 395 | DEBUG("bad hash") 396 | hash_good = "0" 397 | 398 | if sig_pkalgd == "DSA" or sig_pkalgd == "ECDSA": 399 | f.seek(sig_data_offset) 400 | sig_r = mpi_read(f) 401 | sig_s = mpi_read(f) 402 | DEBUG("r: %s" % sig_r) 403 | DEBUG("s: %s" % sig_s) 404 | elif sig_pkalgd[0:3] == "RSA": 405 | f.seek(sig_data_offset) 406 | sig_rsa = mpi_read(f) 407 | else: 408 | sig_r = "" 409 | sig_s = "" 410 | 411 | if (sig_pkalgd == "DSA") and (sig_version in [3, 4]) and (mode == 'sql'): 412 | print("INSERT INTO sigs_dsa (dsa_r, dsa_s, sigtype, hashbits, hash, pkalg, hashalg, keyid, master_keyid, file, keyoffset, sigoffset) VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %i, %i);" % (sig_r, sig_s, sigtype(sig_type), sig_hash_upper_16bits, sig_hash_str, sig_pkalgd, sig_hashalgd, sig_issuer_keyid, last_pubkey_id, filename, last_pubkey_start, packet_start)) 413 | if (sig_pkalgd == "ECDSA") and (sig_version in [3, 4]) and (mode == 'sql'): 414 | print("INSERT INTO sigs_ecc (dsa_r, dsa_s, sigtype, hashbits, hash, pkalg, hashalg, keyid, master_keyid, file, keyoffset, sigoffset) VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %i, %i);" % (sig_r, sig_s, sigtype(sig_type), sig_hash_upper_16bits, sig_hash_str, sig_pkalgd, sig_hashalgd, sig_issuer_keyid, last_pubkey_id, filename, last_pubkey_start, packet_start)) 415 | elif (sig_pkalgd[0:3] == "RSA") and (sig_version in [3, 4]) and (mode == 'sql'): 416 | print("INSERT INTO sigs_rsa (rsa_sig, sigtype, hashbits, hash, pkalg, hashalg, keyid, master_keyid, file, keyoffset, sigoffset) VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %i, %i);" % (sig_rsa, sigtype(sig_type), sig_hash_upper_16bits, sig_hash_str, sig_pkalgd, sig_hashalgd, sig_issuer_keyid, last_pubkey_id, filename, last_pubkey_start, packet_start)) 417 | 418 | 419 | parser = argparse.ArgumentParser() 420 | parser.add_argument('files', metavar='keydump', type=str, nargs='+', 421 | help='Files to parse') 422 | parser.add_argument('--check', action='store_true', 423 | help='check keys/sigs for errors') 424 | parser.add_argument('--primetest', action='store_true', 425 | help='disable test for primality (much faster)') 426 | options = parser.parse_args() 427 | 428 | 429 | if options.check: parse_mode = "check" 430 | else: parse_mode = "sql" 431 | 432 | for filename in options.files: 433 | pgp_parse(filename, parse_mode, options.primetest) 434 | -------------------------------------------------------------------------------- /keyr.sql: -------------------------------------------------------------------------------- 1 | -- phpMyAdmin SQL Dump 2 | -- version 4.2.9.1 3 | -- http://www.phpmyadmin.net 4 | -- 5 | -- Host: localhost 6 | -- Generation Time: Oct 20, 2014 at 01:06 PM 7 | -- Server version: 5.6.21-log 8 | -- PHP Version: 5.6.2-pl0-gentoo 9 | 10 | SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; 11 | SET time_zone = "+00:00"; 12 | 13 | 14 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 15 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; 16 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; 17 | /*!40101 SET NAMES utf8 */; 18 | 19 | -- 20 | -- Database: `pgp` 21 | -- 22 | 23 | -- -------------------------------------------------------- 24 | 25 | -- 26 | -- Table structure for table `keys_dsa` 27 | -- 28 | 29 | CREATE TABLE IF NOT EXISTS `keys_dsa` ( 30 | `id` mediumint(3) unsigned NOT NULL, 31 | `keyid` varchar(16) COLLATE ascii_bin NOT NULL, 32 | `keyid_short` varchar(8) COLLATE ascii_bin NOT NULL, 33 | `keyid_master` varchar(16) COLLATE ascii_bin NOT NULL, 34 | `alg` varchar(8) COLLATE ascii_bin NOT NULL, 35 | `dsa_p` varchar(1024) COLLATE ascii_bin NOT NULL, 36 | `dsa_q` varchar(1024) COLLATE ascii_bin NOT NULL, 37 | `dsa_g` varchar(1024) COLLATE ascii_bin NOT NULL, 38 | `dsa_y` varchar(1024) COLLATE ascii_bin NOT NULL, 39 | `dsa_bits` smallint(2) unsigned NOT NULL, 40 | `ver` tinyint(1) unsigned NOT NULL, 41 | `sub` tinyint(1) unsigned NOT NULL, 42 | `errors` set('p_notprime','q_notprime') COLLATE ascii_bin NOT NULL, 43 | `file` varchar(32) COLLATE ascii_bin NOT NULL, 44 | `keyoffset` int(4) unsigned NOT NULL, 45 | `masteroffset` int(4) unsigned NOT NULL 46 | ) ENGINE=MyISAM DEFAULT CHARSET=ascii COLLATE=ascii_bin; 47 | 48 | -- -------------------------------------------------------- 49 | 50 | -- 51 | -- Table structure for table `keys_ecc` 52 | -- 53 | 54 | CREATE TABLE IF NOT EXISTS `keys_ecc` ( 55 | `id` mediumint(3) unsigned NOT NULL, 56 | `keyid` varchar(16) COLLATE ascii_bin NOT NULL, 57 | `keyid_short` varchar(8) COLLATE ascii_bin NOT NULL, 58 | `keyid_master` varchar(16) COLLATE ascii_bin NOT NULL, 59 | `alg` varchar(8) COLLATE ascii_bin NOT NULL, 60 | `ver` tinyint(1) unsigned NOT NULL, 61 | `curve_type` varchar(11) COLLATE ascii_bin NOT NULL, 62 | `curve_point` varchar(512) COLLATE ascii_bin NOT NULL, 63 | `sub` tinyint(1) unsigned NOT NULL, 64 | `errors` set('p_notprime','q_notprime') COLLATE ascii_bin NOT NULL, 65 | `file` varchar(32) COLLATE ascii_bin NOT NULL, 66 | `keyoffset` int(4) unsigned NOT NULL, 67 | `masteroffset` int(4) unsigned NOT NULL 68 | ) ENGINE=MyISAM DEFAULT CHARSET=ascii COLLATE=ascii_bin; 69 | 70 | -- -------------------------------------------------------- 71 | 72 | -- 73 | -- Table structure for table `keys_rsa` 74 | -- 75 | 76 | CREATE TABLE IF NOT EXISTS `keys_rsa` ( 77 | `id` mediumint(3) unsigned NOT NULL, 78 | `keyid` varchar(16) COLLATE ascii_bin NOT NULL, 79 | `keyid_short` varchar(8) COLLATE ascii_bin NOT NULL, 80 | `keyid_master` varchar(16) COLLATE ascii_bin NOT NULL, 81 | `rsa_n` varchar(4096) COLLATE ascii_bin NOT NULL, 82 | `rsa_e` varchar(1024) COLLATE ascii_bin NOT NULL, 83 | `rsa_bits` smallint(2) unsigned NOT NULL, 84 | `ver` tinyint(1) unsigned NOT NULL, 85 | `sub` tinyint(1) unsigned NOT NULL, 86 | `errors` set('smallfact') COLLATE ascii_bin NOT NULL, 87 | `file` varchar(32) COLLATE ascii_bin NOT NULL, 88 | `keyoffset` int(4) unsigned NOT NULL, 89 | `masteroffset` int(4) unsigned NOT NULL 90 | ) ENGINE=MyISAM DEFAULT CHARSET=ascii COLLATE=ascii_bin; 91 | 92 | -- -------------------------------------------------------- 93 | 94 | -- 95 | -- Table structure for table `sigs_dsa` 96 | -- 97 | 98 | CREATE TABLE IF NOT EXISTS `sigs_dsa` ( 99 | `id` mediumint(3) unsigned NOT NULL, 100 | `dsa_r` varchar(1024) COLLATE ascii_bin NOT NULL, 101 | `dsa_s` varchar(1024) COLLATE ascii_bin NOT NULL, 102 | `sigtype` varchar(32) COLLATE ascii_bin NOT NULL, 103 | `hashbits` varchar(4) COLLATE ascii_bin NOT NULL, 104 | `hash` varchar(128) COLLATE ascii_bin NOT NULL, 105 | `pkalg` varchar(8) COLLATE ascii_bin NOT NULL, 106 | `hashalg` varchar(8) COLLATE ascii_bin NOT NULL, 107 | `keyid` varchar(16) COLLATE ascii_bin NOT NULL, 108 | `master_keyid` varchar(16) COLLATE ascii_bin NOT NULL, 109 | `file` varchar(32) COLLATE ascii_bin NOT NULL, 110 | `keyoffset` int(4) unsigned NOT NULL, 111 | `sigoffset` int(4) unsigned NOT NULL 112 | ) ENGINE=MyISAM DEFAULT CHARSET=ascii COLLATE=ascii_bin; 113 | 114 | -- -------------------------------------------------------- 115 | 116 | -- 117 | -- Table structure for table `sigs_ecc` 118 | -- 119 | 120 | CREATE TABLE IF NOT EXISTS `sigs_ecc` ( 121 | `id` mediumint(3) unsigned NOT NULL, 122 | `dsa_r` varchar(256) COLLATE ascii_bin NOT NULL, 123 | `dsa_s` varchar(256) COLLATE ascii_bin NOT NULL, 124 | `sigtype` varchar(32) COLLATE ascii_bin NOT NULL, 125 | `hashbits` varchar(4) COLLATE ascii_bin NOT NULL, 126 | `hash` varchar(128) COLLATE ascii_bin NOT NULL, 127 | `pkalg` varchar(8) COLLATE ascii_bin NOT NULL, 128 | `hashalg` varchar(8) COLLATE ascii_bin NOT NULL, 129 | `keyid` varchar(16) COLLATE ascii_bin NOT NULL, 130 | `master_keyid` varchar(16) COLLATE ascii_bin NOT NULL, 131 | `file` varchar(32) COLLATE ascii_bin NOT NULL, 132 | `keyoffset` int(4) unsigned NOT NULL, 133 | `sigoffset` int(4) unsigned NOT NULL 134 | ) ENGINE=MyISAM DEFAULT CHARSET=ascii COLLATE=ascii_bin; 135 | 136 | -- -------------------------------------------------------- 137 | 138 | -- 139 | -- Table structure for table `sigs_rsa` 140 | -- 141 | 142 | CREATE TABLE IF NOT EXISTS `sigs_rsa` ( 143 | `id` mediumint(3) unsigned NOT NULL DEFAULT '0', 144 | `rsa_sig` varchar(1024) COLLATE ascii_bin NOT NULL, 145 | `sigtype` varchar(32) COLLATE ascii_bin NOT NULL, 146 | `hashbits` varchar(4) COLLATE ascii_bin NOT NULL, 147 | `hash` varchar(128) COLLATE ascii_bin NOT NULL, 148 | `pkalg` varchar(8) COLLATE ascii_bin NOT NULL, 149 | `hashalg` varchar(8) COLLATE ascii_bin NOT NULL, 150 | `keyid` varchar(16) COLLATE ascii_bin NOT NULL, 151 | `master_keyid` varchar(16) COLLATE ascii_bin NOT NULL, 152 | `file` varchar(32) COLLATE ascii_bin NOT NULL, 153 | `keyoffset` int(4) unsigned NOT NULL, 154 | `sigoffset` int(4) unsigned NOT NULL 155 | ) ENGINE=MyISAM DEFAULT CHARSET=ascii COLLATE=ascii_bin; 156 | 157 | -- 158 | -- Indexes for dumped tables 159 | -- 160 | 161 | -- 162 | -- Indexes for table `keys_dsa` 163 | -- 164 | ALTER TABLE `keys_dsa` 165 | ADD PRIMARY KEY (`id`), ADD KEY `keyid` (`keyid`(4)), ADD KEY `dsa_p` (`dsa_p`(16)), ADD KEY `dsa_q` (`dsa_q`(16)), ADD KEY `dsa_g` (`dsa_g`(16)), ADD KEY `dsa_y` (`dsa_y`(16)); 166 | 167 | -- 168 | -- Indexes for table `keys_ecc` 169 | -- 170 | ALTER TABLE `keys_ecc` 171 | ADD PRIMARY KEY (`id`), ADD KEY `curve_point` (`curve_point`(16)); 172 | 173 | -- 174 | -- Indexes for table `keys_rsa` 175 | -- 176 | ALTER TABLE `keys_rsa` 177 | ADD PRIMARY KEY (`id`), ADD KEY `keyid` (`keyid`(4)), ADD KEY `rsa_n` (`rsa_n`(16)), ADD KEY `rsa_e` (`rsa_e`(4)); 178 | 179 | -- 180 | -- Indexes for table `sigs_dsa` 181 | -- 182 | ALTER TABLE `sigs_dsa` 183 | ADD PRIMARY KEY (`id`), ADD KEY `dsa_r` (`dsa_r`(16)), ADD KEY `dsa_s` (`dsa_s`(16)); 184 | 185 | -- 186 | -- Indexes for table `sigs_ecc` 187 | -- 188 | ALTER TABLE `sigs_ecc` 189 | ADD PRIMARY KEY (`id`), ADD KEY `dsa_r` (`dsa_r`(16)), ADD KEY `dsa_s` (`dsa_s`(16)); 190 | 191 | -- 192 | -- Indexes for table `sigs_rsa` 193 | -- 194 | ALTER TABLE `sigs_rsa` 195 | ADD KEY `rsa_sig` (`rsa_sig`(16)); 196 | 197 | -- 198 | -- AUTO_INCREMENT for dumped tables 199 | -- 200 | 201 | -- 202 | -- AUTO_INCREMENT for table `keys_dsa` 203 | -- 204 | ALTER TABLE `keys_dsa` 205 | MODIFY `id` mediumint(3) unsigned NOT NULL AUTO_INCREMENT; 206 | -- 207 | -- AUTO_INCREMENT for table `keys_ecc` 208 | -- 209 | ALTER TABLE `keys_ecc` 210 | MODIFY `id` mediumint(3) unsigned NOT NULL AUTO_INCREMENT; 211 | -- 212 | -- AUTO_INCREMENT for table `keys_rsa` 213 | -- 214 | ALTER TABLE `keys_rsa` 215 | MODIFY `id` mediumint(3) unsigned NOT NULL AUTO_INCREMENT; 216 | -- 217 | -- AUTO_INCREMENT for table `sigs_dsa` 218 | -- 219 | ALTER TABLE `sigs_dsa` 220 | MODIFY `id` mediumint(3) unsigned NOT NULL AUTO_INCREMENT; 221 | -- 222 | -- AUTO_INCREMENT for table `sigs_ecc` 223 | -- 224 | ALTER TABLE `sigs_ecc` 225 | MODIFY `id` mediumint(3) unsigned NOT NULL AUTO_INCREMENT; 226 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 227 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; 228 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; 229 | --------------------------------------------------------------------------------