You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Java基于大素数与公钥指数计算Tor洋葱地址

Hey there! Let's walk through exactly how to generate a Tor onion address in Java for both of your use cases. Tor onion addresses are derived from the SHA-1 hash of the DER-encoded RSA public key, so we'll focus on building that key correctly from your inputs first.

1. Generating Tor Onion Address from Two Large Primes

When you only have primes p and q, we'll use the standard RSA public exponent e = 65537 (0x10001) since this is the most common choice for Tor services. Here's the full implementation:

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import com.google.common.io.BaseEncoding;

public class TorOnionGenerator {
    public static void main(String[] args) throws NoSuchAlgorithmException {
        // Your provided large primes (ensure q is fully populated with its complete value)
        BigInteger p = new BigInteger("14083359469338511572632447718747493405040362318205860500297736061630222431052998057250747900577940212317413063");
        BigInteger q = new BigInteger("769214211067601252855509292409033549663704318277927149200860114881039520949691757314599081173759953492458...");

        // Step 1: Calculate RSA modulus n = p * q
        BigInteger n = p.multiply(q);

        // Step 2: Use standard public exponent e = 65537
        BigInteger e = new BigInteger("65537");

        // Step 3: Encode the RSA public key to ASN.1 DER format (required for Tor)
        byte[] derPublicKey = encodeRsaPublicKeyToDer(n, e);

        // Step 4: Compute SHA-1 hash of the DER-encoded key
        MessageDigest sha1Digest = MessageDigest.getInstance("SHA-1");
        byte[] sha1Hash = sha1Digest.digest(derPublicKey);

        // Step 5: Take the first 16 bytes of the hash (Tor uses this for the address)
        byte[] onionHashBytes = new byte[16];
        System.arraycopy(sha1Hash, 0, onionHashBytes, 0, 16);

        // Step 6: Encode to Base32 (Tor uses lowercase, no padding)
        String onionAddress = BaseEncoding.base32().encode(onionHashBytes).toLowerCase() + ".onion";

        System.out.println("Generated Onion Address: " + onionAddress);
    }

    // Helper to encode RSA public key (n, e) to ASN.1 DER format
    private static byte[] encodeRsaPublicKeyToDer(BigInteger modulus, BigInteger exponent) {
        try {
            byte[] encodedModulus = encodeBigIntegerToDerInteger(modulus);
            byte[] encodedExponent = encodeBigIntegerToDerInteger(exponent);
            return wrapInDerSequence(encodedModulus, encodedExponent);
        } catch (Exception ex) {
            throw new RuntimeException("Failed to encode RSA public key to DER", ex);
        }
    }

    // Encode a BigInteger to DER INTEGER type (handles leading zeros/sign rules)
    private static byte[] encodeBigIntegerToDerInteger(BigInteger value) {
        byte[] rawBytes = value.toByteArray();

        // Remove unnecessary leading zero (primes/modulus are positive, so this is safe)
        if (rawBytes.length > 1 && rawBytes[0] == 0x00) {
            byte[] trimmed = new byte[rawBytes.length - 1];
            System.arraycopy(rawBytes, 1, trimmed, 0, trimmed.length);
            rawBytes = trimmed;
        }

        // Prepend zero if first byte is 0x80+ (to avoid being interpreted as negative)
        if ((rawBytes[0] & 0x80) != 0) {
            byte[] adjusted = new byte[rawBytes.length + 1];
            adjusted[0] = 0x00;
            System.arraycopy(rawBytes, 0, adjusted, 1, rawBytes.length);
            return adjusted;
        }

        return rawBytes;
    }

    // Wrap DER elements in a SEQUENCE tag (required for RSA public key structure)
    private static byte[] wrapInDerSequence(byte[]... elements) {
        int totalElementLength = 0;
        for (byte[] elem : elements) totalElementLength += elem.length;

        byte[] lengthBytes = encodeDerLength(totalElementLength);

        // Build the full sequence: 0x30 (SEQUENCE tag) + length + elements with INTEGER tags
        byte[] sequence = new byte[1 + lengthBytes.length + totalElementLength];
        sequence[0] = 0x30;
        System.arraycopy(lengthBytes, 0, sequence, 1, lengthBytes.length);

        int offset = 1 + lengthBytes.length;
        for (byte[] elem : elements) {
            sequence[offset++] = 0x02; // INTEGER tag
            byte[] elemLength = encodeDerLength(elem.length);
            System.arraycopy(elemLength, 0, sequence, offset, elemLength.length);
            offset += elemLength.length;
            System.arraycopy(elem, 0, sequence, offset, elem.length);
            offset += elem.length;
        }

        return sequence;
    }

    // Encode length value to DER format
    private static byte[] encodeDerLength(int length) {
        if (length < 0x80) {
            return new byte[]{(byte) length};
        } else {
            byte[] lengthBytes = BigInteger.valueOf(length).toByteArray();
            byte[] result = new byte[lengthBytes.length + 1];
            result[0] = (byte) (0x80 + lengthBytes.length);
            System.arraycopy(lengthBytes, 0, result, 1, lengthBytes.length);
            return result;
        }
    }
}

Key Notes for This Scenario:

  • We use Guava's BaseEncoding for reliable Base32 conversion (you'll need to add this dependency to your project—see below).
  • The DER encoding follows strict ASN.1 rules; the helper methods handle edge cases like leading zeros in integers.
  • Tor requires the first 16 bytes of the SHA-1 hash of the DER public key for the address.
2. Generating Tor Onion Address from Primes + Public Exponent

This is nearly identical to the first case—you just replace the default exponent 65537 with your provided public exponent. Here's the only change you need to make:

// Replace this line with your given public exponent
BigInteger e = new BigInteger("YOUR_PROVIDED_PUBLIC_EXPONENT");

Everything else in the code (modulus calculation, DER encoding, hashing, Base32 conversion) stays exactly the same.

Dependency Setup (Guava)

If you're using Maven, add this to your pom.xml to include Guava:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>32.1.3-jre</version> <!-- Use the latest stable version -->
</dependency>

For Gradle:

implementation 'com.google.guava:guava:32.1.3-jre'

Important Reminders

  • Ensure your primes p and q are valid, large primes (Tor supports 1024-bit or 2048-bit RSA keys; your provided primes appear to be 2048-bit, which is acceptable).
  • Double-check that your public exponent e is valid (it must be coprime with (p-1)*(q-1)).

内容的提问来源于stack exchange,提问作者user728785

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:15:15