Did you look at RSAKeyPairGenerator
(doc)(source) from BouncyCastle? It generates an RSA keypair and encodes it. I bet you can create a keypair object, fill it with your values and call the encoding function to get a file gpg will accept.
EDIT:
So I've used openssl to generate an RSA keypair and export the values of its components:
openssl genrsa -out rsa1024.pem 1024
openssl rsa -noout -text -in rsa1024.pem
I've removed the colon byte separators and newlines from the big int values and padded the exponent to be an even number of nibbles in hex.
If you apply the following patch to this file:
--- bcpg-jdk15on-152/org/bouncycastle/openpgp/examples/RSAKeyPairGenerator.java 2015-03-01 12:03:48.000000000 +0200
+++ src/foo/RSAKeyPairGenerator.java 2015-05-19 23:07:00.754583435 +0300
@@ -1,11 +1,13 @@
-package org.bouncycastle.openpgp.examples;
+package foo;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
+import java.lang.reflect.Constructor;
+import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.KeyPair;
-import java.security.KeyPairGenerator;
+//import java.security.KeyPairGenerator;
import java.security.NoSuchProviderException;
import java.security.Security;
import java.security.SignatureException;
@@ -13,6 +15,10 @@
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.bcpg.HashAlgorithmTags;
+import org.bouncycastle.crypto.params.RSAKeyParameters;
+import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPrivateCrtKey;
+import org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.PGPEncryptedData;
import org.bouncycastle.openpgp.PGPException;
@@ -76,11 +82,34 @@
{
Security.addProvider(new BouncyCastleProvider());
- KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "BC");
+ //KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "BC");
- kpg.initialize(1024);
+ //kpg.initialize(1024);
- KeyPair kp = kpg.generateKeyPair();
+ //KeyPair kp = kpg.generateKeyPair();
+
+ BigInteger modulus = new BigInteger("00f4035469c2adf91d69052f94a8d466cae6ea485ecfd0dc6b1d408e8ef36ef2a60d907234c4e9e8e1261e42008a41140134fc62840338433ab5948b96ceb91b65b0aacf8b54deca21a90386ebe17df16ebd1bef137ba8a43e9e2671ecd0bc5cd052321d50e61eac532cf718309f76760b9e68690897d76a5f9955541f3bd87a89", 16);
+ BigInteger publicExponent = new BigInteger("010001", 16);
+ BigInteger privateExponent = new BigInteger("00abfc6cd2de54a0f109c48df4c9ca6b6937b889a9c9effc6bc3026d78743c0eeadb44a43a6d5030c40089f31b4e56f032a995fa19f1eb05f7ab6437bee395b4a867af07b71b8515728b44fed0f5c85367e182a00a8df3df3098b82e74f224b294c90e261869c81fb9b89824bec026b7189bad0c11d4366636e2d357ca06e591c1", 16);
+ BigInteger p = new BigInteger("00fdd4b067e9361abe40231470f8249e68d64aeade1828dcd8b60cb33942df55bb6806fa81784b5fc24f73d8313baac2c0150307e56df621c77cc650b2b6996193", 16);
+ BigInteger q = new BigInteger("00f619297aa83e72f5a0c9b0df87c1bb0927c17d70cf99c6a9f6c58ddbb848d40abdd0c853baf7de55ac8dfe84ba38d12e86703e4b82273066c252369a5f3534f3", 16);
+ BigInteger dP = new BigInteger("4dbd9e69b4db85454f8f6eeb4a94ac8f9f5242acd2e970fa4e87853cbc667a737360efc847778e548cd1061dce1076a52dca47d8d4dcd56baba37183cab91f51", 16);
+ BigInteger dQ = new BigInteger("64232af0a103002e1865d955ab5cd6294c86fbeeea5a6d2efd9db7325f932accd01de355c6af5345d337d807d3ea889b80d2ad56763852068e2d7bd066cb34a7", 16);
+ BigInteger qInv = new BigInteger("00c9cbb6242b3e748d557e12cbacaa4b3e5a7fd0573fcc31b77268a492e270055628a02a46ff4cefbdff28aaea289faca9826d8e22cf5b0f4de2e15bdd4b3d3d14", 16);
+
+ RSAKeyParameters pubkey_params = new RSAKeyParameters(false, modulus, publicExponent);
+ RSAPrivateCrtKeyParameters privkey_params = new RSAPrivateCrtKeyParameters(
+ modulus, publicExponent, privateExponent, p, q, dP, dQ, qInv);
+
+ Constructor<BCRSAPublicKey> pubkeyctor = BCRSAPublicKey.class.getDeclaredConstructor(RSAKeyParameters.class);
+ pubkeyctor.setAccessible(true);
+ BCRSAPublicKey pubkey = pubkeyctor.newInstance(pubkey_params);
+
+ Constructor<BCRSAPrivateCrtKey> privkeyctor = BCRSAPrivateCrtKey.class.getDeclaredConstructor(RSAPrivateCrtKeyParameters.class);
+ privkeyctor.setAccessible(true);
+ BCRSAPrivateCrtKey privkey = privkeyctor.newInstance(privkey_params);
+
+ KeyPair kp = new KeyPair(pubkey, privkey);
if (args.length < 2)
{
You'll get a program which when run with arguments "-a foo password" produces pub.asc and secret.asc files which are a pgp keypair.
EDIT 2:
$ pgpdump secret.asc
Old: Secret Key Packet(tag 5)(510 bytes)
Ver 4 - new
Public key creation time - Tue May 19 22:56:20 IDT 2015
Pub alg - RSA Encrypt or Sign(pub 1)
RSA n(1024 bits) - ...
RSA e(17 bits) - ...
Sym alg - CAST5(sym 3)
Iterated and salted string-to-key(s2k 3):
Hash alg - SHA1(hash 2)
Salt - 3b b9 cf f9 02 cf 90 9e
Count - 65536(coded count 96)
IV - d8 ac aa 96 61 7a 03 34
Encrypted RSA d
Encrypted RSA p
Encrypted RSA q
Encrypted RSA u
Encrypted SHA1 hash
Old: User ID Packet(tag 13)(2 bytes)
User ID - id
Old: Signature Packet(tag 2)(156 bytes)
Ver 4 - new
Sig type - Generic certification of a User ID and Public Key packet(0x10).
Pub alg - RSA Encrypt or Sign(pub 1)
Hash alg - SHA1(hash 2)
Hashed Sub: signature creation time(sub 2)(4 bytes)
Time - Tue May 19 22:56:20 IDT 2015
Sub: issuer key ID(sub 16)(8 bytes)
Key ID - 0xB01AC717560C7F68
Hash left 2 bytes - ee a9
RSA m^d mod n(1024 bits) - ...
-> PKCS-1
b = 2048;RandomPrime[{2^(b - 1), 2^b - 1}]
) even thoughPrimePi
and other functions fail on primes larger than about 45 bits. However, I'm still curious is GPG enforces a limit on imported keys.