在 Windows 10 上,如何自动生成 PGP RSA 密钥对,如果 40 个十六进制字符指纹未开始ABBA
(例如)转储每个,当生成的一对满足该标准时停止,然后导出公共和私人标准 ASCII 装甲形式的钥匙?假设所有指纹都是等概率的,在本例中,预期生成的指纹对数量约为 45,000,手动处理太多。
我不确定在 Windows 中是否有好的方法来执行此操作。
我最终只是为了好玩而对此进行了一些修改,并想出了一个可以在 Linux 和 Windows 中运行的新 python 脚本。它不需要gpgsplit
直接读取导出的密钥。该脚本还运行所有命令,包括生成、导出和导入密钥 - 除了--edit-key
用户必须手动执行的过程结束部分之外的所有命令。您所要做的就是运行脚本然后编辑密钥。
Windows 中未安装 Python 3,因此您需要安装它。您可以从Microsoft Store获取它,也可以从 Python 网站下载它。
只需将下面的脚本保存keychanger.py
在您想要的任何目录中,然后在同一目录中打开终端或 powershell 并输入python keychanger.py
. 它会提示用户输入,告诉它您希望指纹以什么十六进制字符串开头以及要使用的密钥算法(提示包括一些有用的信息)。删除创建的密钥时,gpg 会有提示(必须确认删除 3 次;没有办法解决这个问题)。
请注意,Windows 似乎按字面解释该--passphrase ''
选项,并且密钥不是没有密码,而是有两个单引号作为密码。如果您在脚本运行时看到弹出 pinentry,请输入''
密码。您可以在脚本运行后编辑密钥时更改此密码。我在脚本输出中包含了编辑密钥的说明,以便您在需要时可以在屏幕上查看它。
此外,Powershell 和命令提示符都不允许复制/粘贴命令,除非您通过右键单击其标题栏,选择“首选项”并选中“使用 Ctrl+Shift+V/C 作为复制/粘贴”复选框来启用它。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# keychanger.py - a script to create PGP keys with fingerprints begining
# with a custom hex string.
# Requires GnuPG 2.2.x or later and Python 3.4 or later
#
#
# Max number of iterations to try before giving up:
limit = 1209600
# If the script fails to find a match for your target, try increasing
# this number. Note that this is equivalent to the maximum number of
# seconds to subtract from the timestamp. The default of 1209600 is 2
# weeks and should be sufficient to find any 4 character or less hex
# string. One year is 31557600 seconds. Longer string lengths require a
# greater number of iterations.
########################################################################
# ! ! ! DON'T CHANGE ANYTHING FROM THIS POINT ON ! ! ! #
# ! ! ! UNLESS YOU REALLY KNOW WHAT YOU'RE DOING. ! ! ! #
########################################################################
algos = {'rsa', 'rsa1024', 'rsa2048', 'rsa3072', 'rsa4096', 'dsa', 'dsa1024', 'dsa2048', 'ed25519', 'nistp256', 'nistp384', 'nistp521', 'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1', 'secp256k1'}
# Message prompts for user input
P = ["\nEnter the target hex string you want the key fingerprint to start with.\nIf you want to match a string longer than 4 characters, you'll need to increase to iteration 'limit' value in the script.\n\nEnter hex string target> ","\nChoose the algorithm for the signing key. Valid signing key algorithms are:\n rsa rsa1024 rsa2048 rsa3072 rsa4096\n dsa dsa1024 dsa2048 dsa3072\nGnuPG also allows elliptic curve key algorithms:\n ed25519\n nistp256 nistp384 nistp521\n brainpoolP256r1 brainpoolP384r1 brainpoolP512r1\n secp256k1\n(note: some elliptic curve algorithms might not be available in your version of GnuPG)\n\nEnter key algorithm> "]
def hexcheck(target):
digits = '0123456789abcdef'
target = target.lower()
return set(list(target)).issubset(list(digits))
target = input(P[0])
while hexcheck(target) == False:
print("String contains non-hex digits. Try again.")
target = input(P[0])
target = target.lower()
algo = input(P[1])
while algo not in algos:
print("Algorithm not in list. Try again.\n")
algo = input(P[1])
import hashlib, time, subprocess, uuid, pathlib
# Set user ID and generated file names to random strings.
# This is to ensure none of them already exist
user_id = str(uuid.uuid4())
public_key = str(uuid.uuid4())
secret_key = str(uuid.uuid4())
# Commands to generate, export, then delete the generated keys
cmd1 = ["gpg --quiet --batch --pinentry-mode loopback --passphrase '' --quick-gen-key "+user_id+" "+algo, "gpg --quiet -o "+public_key+" --export "+user_id,"gpg --quiet -o "+secret_key+" --export-secret-keys "+user_id, "gpg --quiet --yes --delete-secret-and-public-keys "+user_id]
for c in cmd1:
subprocess.call(c, shell=True)
# Functions to read gpg exported key data and list individual packets
def header_info(x):
if x[0]&64 == 64:
tag = x[0]&63
if x[1] < 192: [hlen,plen] = [2,x[1]]
elif x[1] <= 223: [hlen,plen] = [3,((x[1] - 192) << 8) + x[2] + 192]
elif x[1] == 255: [hlen,plen] = [5,int.from_bytes(x[2:6],byteorder='big',signed=False)]
else:
tag = (x[0]&60)>>2
if x[0]&3 == 0: [hlen,plen] = [2,x[1]]
elif x[0]&3 == 1: [hlen,plen] = [3,int.from_bytes(x[1:3],byteorder='big',signed=False)]
elif x[0]&3 == 2: [hlen,plen] = [5,int.from_bytes(x[1:5],byteorder='big',signed=False)]
return [tag, hlen, plen]
def splitpackets(x):
packets = []
i = 0
while i < (len(x)-1):
h = header_info(x[i:i+5])
tag = h[0]
packet = x[i:i+h[1]+h[2]]
i += (h[1]+h[2])
packets.append([tag,packet])
return packets
# Rewrite secret_key file without signature packet
with open(secret_key, 'rb') as f:
key = bytes(f.read())
key = splitpackets(key)
key = b''.join([x[1] for x in key if x[0] in {5,13}])
with open(secret_key, 'wb') as f:
f.write(key)
# Get public_key packet
with open(public_key,'rb') as f:
key = bytes(f.read())
# Define header and packet length (subject to adjustment in next step).
hlen = 3
plen = int.from_bytes(key[1:3],byteorder='big',signed=False)
# Make sure public key header is properly formed for calculating the
# fingerprint by verifying the first byte is 0x99. In practice the only
# times this wouldn't be the case is for rsa1024 and elliptic curve
# algorithms whose smaller key size means the packet length can be
# encoded in a single byte.
if key[0] != 0x99:
# Check that header is "old" format (should be, but just in case...)
if key[0]&64 == 0:
hlen = 2
plen = key[1]
else:
# "New" format header. Irregular but not invalid format for a
# key packet header.
if key[1] < 192:
hlen = 2
plen=key[2]
elif key[1] <= 223:
plen = ((key[1] - 192) << 8) + key[2] + 192
# Canonicalize header for fingerprinting. Fingerprint is calculated
# over the packet data with a 3 byte header consisting of 0x99 and a 2-
# byte big endian number that is a count of bytes in the packet data.
h = b'\x99'+plen.to_bytes(2,byteorder='big',signed=False)
key = bytearray(h+key[hlen:hlen+plen])
# Extract current timestamp
timestamp = int.from_bytes(key[4:8],byteorder='big',signed=True)
# Set length of string to match
L = len(target)
# Set the initial hash value and iteration counter.
fingerprint = hashlib.sha1()
fingerprint.update(key)
current = fingerprint.hexdigest()[0:L]
i = 0
# Timer to measure duration of search.
start = time.time()
# Begin search for fingerprint string match
while current != target and i < limit:
fingerprint = hashlib.sha1()
timestamp -= 1
i += 1
key[4:8] = timestamp.to_bytes(4,byteorder='big',signed=True)
fingerprint.update(key)
current = fingerprint.hexdigest()[0:L]
# Stop time for timer.
end = time.time()
if current == target:
# Success :)
with open(secret_key,'r+b') as f:
# Go to start of timestamp in exported secret_key file
f.seek(hlen+1)
# Overwrite timestamp with the one found in the while loop
f.write(bytes(key[4:8]))
print("\nDone "+str(i)+" iterations. Total time: "+str(end-start)+" seconds\n")
# List of commands to import key and display fingerprint
cmd2 = ["gpg --quiet --allow-non-selfsigned-uid --import "+secret_key, "gpg -K "+user_id]
for c in cmd2:
subprocess.call(c, shell=True)
print("\nYOU NEED TO EDIT THIS KEY.\nEnter 'gpg --edit-key "+user_id+"' then use the following commands after the 'gpg>' prompt in the order shown:\n gpg> adduid ...add a new user ID by following the prompts.\n gpg> 1 ...selects the '"+user_id+"' user id\n gpg> deluid ...delete the selected user ID then confirm.\n gpg> change-usage ...toggle usage options until it shows 'Current allowed actions: Sign Certify' then enter Q.\n gpg> passwd ...set a password\n gpg> addkey ...follow prompts to add encryption subkey\n gpg> save ...save the changes made in editing mode")
else:
# Failure :(
print("Failed to match "+str(target)+" in "+str(i)+" iterations. Total time: "+str(end-start)+" seconds")
# Remove generated key files
pathlib.Path(public_key).unlink()
pathlib.Path(secret_key).unlink()
Run Code Online (Sandbox Code Playgroud)
指纹只是公钥数据包的 SHA1 哈希值 - 并且该数据包包含时间戳。这意味着您可以通过仅增量更改时间戳来从同一密钥生成新指纹。
细节可能听起来有点复杂,但是做起来非常快速且容易。
该脚本的工作原理是将密钥数据包时间戳向后递增 1,然后将生成的数据包输入 sha1,以检查指纹是否以每次迭代所选的十六进制字符串开头。
当它找到以与目标字符串匹配的十六进制字符开头的指纹时,它会停止迭代并使用将生成所需指纹的时间戳覆盖密钥中的时间戳。
然后它将新密钥导入到 gpg 并删除脚本创建的文件。
现在您需要使用 gpg 编辑密钥以准备实际使用。需要添加新的用户 ID,需要删除旧的(未签名)用户 ID,密钥用途需要设置为仅“SC”(签名,证明),需要设置密码,并且需要加密子密钥待创建。然后需要保存这些更改。
$ gpg --edit-key <some long uuid>
Run Code Online (Sandbox Code Playgroud)
查看 uuid 的脚本输出。它将显示您可以复制/粘贴的完整编辑键命令。
接下来的所有命令都在编辑键菜单的上下文中输入。
adduid
它将提示您输入“真实姓名”、“电子邮件地址”和“评论”(即,与您通常生成密钥时 gpg 所做的相同)。按照提示进行操作,并o
在提示接受您为用户 ID 输入的数据时输入。
1
选择第一个用户 ID。然后输入:deluid
它会要求您确认删除用户 ID。进入y
。
adduid
通过在 gpg> 提示符下输入以下内容来更改密钥用法(请注意,您必须在执行此操作之前执行此步骤):change-usage
它将显示Current allowed actions: Sign Certify Encrypt Authenticate
,因为这是主键,所以只能是签名和认证。按 Entere
键关闭加密功能,然后按 Entera
键关闭身份验证功能。现在它应该显示Current allowed actions: Sign Certify
我们想要的内容,所以输入q
。
passwd
将弹出一个密码输入窗口 - 输入您要使用的密码。
addkey
然后选择密钥类型,然后在出现提示时输入密码。
save
这将返回到命令提示符。您可以在密钥编辑过程中随时执行此操作。您现在拥有一个功能齐全的自定义指纹钥匙。