如何用Java生成Tor洋葱服务的有效RSA 1024私钥并获取.onion地址
嘿,我来帮你搞定用Java生成有效Tor洋葱服务私钥的问题!你现在尝试的RSA 1024位密钥其实对应Tor v2洋葱服务的规范,但目前Tor已经逐步淘汰v2了,我会同时给你v2兼容版和当前推荐的v3标准版的实现方案。
首先先明确核心要点:
- Tor v2洋葱服务:依赖1024位RSA密钥,私钥需为PKCS#1格式(Java默认生成的是PKCS#8,需要转换),.onion地址由公钥的SHA-1哈希前8字节做Base32编码得到
- Tor v3洋葱服务:使用ED25519密钥(当前安全标准),.onion地址由公钥的Blake2b-256哈希前32字节做Base32编码得到
方案1:生成Tor v2洋葱服务密钥(兼容旧版本)
你之前的代码已经生成了RSA密钥,但没转换成Tor需要的PKCS#1格式,这里用BouncyCastle工具类来处理格式转换(Java标准库没有直接的PKCS#1转换工具):
首先引入BouncyCastle依赖(Maven为例):
<dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.70</version> </dependency>
完整实现代码:
import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1SequenceGenerator; import org.bouncycastle.asn1.ASN1BitString; import org.bouncycastle.asn1.ASN1InputStream; import java.security.*; import java.security.spec.RSAPrivateKeySpec; import java.util.Base64; import java.io.ByteArrayOutputStream; public class TorV2KeyGenerator { public static void main(String[] args) throws Exception { // 生成符合Tor v2要求的1024位RSA密钥对 KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); keyGen.initialize(1024, new SecureRandom()); KeyPair keyPair = keyGen.generateKeyPair(); PrivateKey privateKey = keyPair.getPrivate(); PublicKey publicKey = keyPair.getPublic(); // 将Java默认的PKCS#8私钥转换为Tor需要的PKCS#1格式 KeyFactory keyFactory = KeyFactory.getInstance("RSA"); RSAPrivateKeySpec rsaPrivateSpec = keyFactory.getKeySpec(privateKey, RSAPrivateKeySpec.class); byte[] pkcs1PrivateBytes = buildPKCS1PrivateKey(rsaPrivateSpec); // 输出Base64编码的私钥(可直接填入Tor配置的HiddenServicePrivateKey字段) String base64PrivateKey = Base64.getEncoder().encodeToString(pkcs1PrivateBytes); System.out.println("Tor v2私钥(Base64): " + base64PrivateKey); // 生成对应的.onion地址 byte[] rsaPublicKeyBytes = extractRSAPublicKeyFromX509(publicKey.getEncoded()); MessageDigest sha1 = MessageDigest.getInstance("SHA-1"); byte[] hash = sha1.digest(rsaPublicKeyBytes); byte[] onionPrefix = new byte[8]; System.arraycopy(hash, 0, onionPrefix, 0, 8); // 适配Tor的Base32规则:全小写、无填充符 String onionAddress = Base32.encode(onionPrefix).toLowerCase().replaceAll("=", "") + ".onion"; System.out.println("Tor v2洋葱地址: " + onionAddress); } // 手动构造PKCS#1格式的RSA私钥DER编码 private static byte[] buildPKCS1PrivateKey(RSAPrivateKeySpec spec) throws Exception { ASN1SequenceGenerator seqGen = new ASN1SequenceGenerator(new ByteArrayOutputStream()); seqGen.addObject(new ASN1Integer(0)); // 版本号 seqGen.addObject(new ASN1Integer(spec.getModulus())); seqGen.addObject(new ASN1Integer(spec.getPublicExponent())); seqGen.addObject(new ASN1Integer(spec.getPrivateExponent())); seqGen.addObject(new ASN1Integer(spec.getPrimeP())); seqGen.addObject(new ASN1Integer(spec.getPrimeQ())); seqGen.addObject(new ASN1Integer(spec.getExponentP())); seqGen.addObject(new ASN1Integer(spec.getExponentQ())); seqGen.addObject(new ASN1Integer(spec.getCrtCoefficient())); return seqGen.getOutputStream().toByteArray(); } // 从X.509格式的公钥中提取原始RSA公钥部分 private static byte[] extractRSAPublicKeyFromX509(byte[] x509Bytes) throws Exception { try (ASN1InputStream asn1In = new ASN1InputStream(x509Bytes)) { ASN1Sequence seq = (ASN1Sequence) asn1In.readObject(); ASN1BitString publicKeyBitString = (ASN1BitString) seq.getObjectAt(1); return publicKeyBitString.getBytes(); } } }
方案2:生成Tor v3洋葱服务密钥(当前推荐)
Tor v3是官方主推的安全标准,依赖ED25519密钥,同样需要BouncyCastle支持:
import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.generators.Ed25519KeyPairGenerator; import org.bouncycastle.crypto.params.Ed25519KeyGenerationParameters; import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters; import org.bouncycastle.crypto.params.Ed25519PublicKeyParameters; import org.bouncycastle.crypto.digests.Blake2bDigest; import org.bouncycastle.util.encoders.Base32; import java.security.SecureRandom; import java.util.Base64; public class TorV3KeyGenerator { public static void main(String[] args) { // 生成ED25519密钥对 Ed25519KeyPairGenerator keyGen = new Ed25519KeyPairGenerator(); keyGen.init(new Ed25519KeyGenerationParameters(new SecureRandom())); AsymmetricCipherKeyPair keyPair = keyGen.generateKeyPair(); Ed25519PrivateKeyParameters privateKeyParams = (Ed25519PrivateKeyParameters) keyPair.getPrivate(); Ed25519PublicKeyParameters publicKeyParams = (Ed25519PublicKeyParameters) keyPair.getPublic(); // 生成Tor v3洋葱地址:公钥做Blake2b-256哈希,取前32字节Base32编码 byte[] publicKeyBytes = publicKeyParams.getEncoded(); Blake2bDigest blake2b = new Blake2bDigest(256); blake2b.update(publicKeyBytes, 0, publicKeyBytes.length); byte[] hash = new byte[blake2b.getDigestSize()]; blake2b.doFinal(hash, 0); String onionAddress = Base32.encode(hash).toLowerCase().replaceAll("=", "") + ".onion"; System.out.println("Tor v3洋葱地址: " + onionAddress); // 输出PKCS#8格式的PEM私钥(可直接用于Tor配置) byte[] privateKeyBytes = privateKeyParams.getEncoded(); String pemPrivateKey = "-----BEGIN PRIVATE KEY-----\n" + Base64.getEncoder().encodeToString(privateKeyBytes) + "\n-----END PRIVATE KEY-----"; System.out.println("Tor v3私钥(PEM格式):\n" + pemPrivateKey); } }
关键注意事项
- 依赖BouncyCastle:Java标准库对ASN.1格式处理和ED25519原生支持有限,必须引入第三方库完成格式转换
- Base32编码适配:Tor使用无填充、全小写的Base32编码,需要手动去掉编码后的
=填充符 - 版本选择:Tor v2已被官方弃用,大部分公共Tor节点不再支持,优先选择v3方案
内容的提问来源于stack exchange,提问作者user728785
相关产品推荐
相关产品推荐

