I keep on getting java.security.NoSuchAlgorithmException: no such algorithm: AES for provider BC with my code below. It looks like I have included all the things I need.
My class is as follows:
....
import org.bouncycastle.jce.provider.BouncyCastleProvider;
class ... {
static
{
Security.addProvider(new BouncyCastleProvider());
}
public CryptSession(String _algo, String _provider, String _keyAlgo, int _keySize)
throws
NoSuchAlgorithmException,
NoSuchProviderException
{
KeyGenerator generator = KeyGenerator.getInstance("AES", "BC"); // KeyGenerator.getInstance(_algo, _provider);
generator.init(256); //generator.init(_keySize);
this._algo = _algo;
this._provider = _provider;
this._keyAlgo = _keyAlgo;
this._keySize = _keySize;
this._key = generator.generateKey();
}
...
You need to edit java security policy file add bauntycasle provider to policy file located in jdk/bin/lib directory
Related
I receive this error:
com.nimbusds.jose.JOSEException: Invalid private RSA key: Keystore operation failed
And my java.class:
public class MyClass {
private static final String ANDROID_PROVIDER = "AndroidKeyStore";
#RequiresApi(api = Build.VERSION_CODES.M)
public static PublicKey getPublicKeyAndCreateKeypairIfNotExists(String alias) throws GeneralSecurityException, IOException {
KeyStore keyStore = KeyStore.getInstance(ANDROID_PROVIDER);
keyStore.load(null);
if (!keyStore.containsAlias(alias) || keyStore.getCertificate(alias) == null) {
KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
alias,
KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
.setBlockModes(KeyProperties.BLOCK_MODE_ECB)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
.setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
.build();
KeyPairGenerator generator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, ANDROID_PROVIDER);
generator.initialize(spec);
generator.generateKeyPair();
}
return keyStore.getCertificate(alias).getPublicKey();
}
#RequiresApi(api = Build.VERSION_CODES.M)
public static PrivateKey getSecretKey(String alias) throws GeneralSecurityException, IOException {
KeyStore.Entry entry;
//Get Android KeyStore
KeyStore ks = KeyStore.getInstance(ANDROID_PROVIDER);
// Weird artifact of Java API. If you don't have an InputStream to load, you still need to call "load", or it'll crash.
ks.load(null);
// Load the key pair from the Android Key Store
entry = ks.getEntry(alias, null);
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)entry;
PrivateKey privateKey = privateKeyEntry.getPrivateKey();
return privateKey;
}
public static String createJWT(String alias) throws JSONException, GeneralSecurityException, IOException, JOSEException {
//
RSASSASigner signer = new RSASSASigner(getSecretKey(alias));
//signer.getJCAContext().setProvider(hsmProvider);
//
SignedJWT jwt = new SignedJWT(
new JWSHeader.Builder(JWSAlgorithm.RS256).keyID(alias).build(),
new JWTClaimsSet.Builder().subject("alice").build());
jwt.sign(signer);
String jwtString = jwt.serialize();
return jwtString;
}
}
The error appears specifically when executing the createJWT method on the line:
jwt.sign(signer);
Apparently the creation of the Keypair is satisfactory, since I have previously tested it and it does not give any error, even with ENCRYPT and DECRYPT it works perfectly. The problem is in the createJWT() method. I really don't know what I'm doing wrong.
Thanks in advance
I ran into this same issue. when i looked into the end of stack trace, the exception was
Caused by: android.security.KeyStoreException: **Incompatible padding mode**
And fixed by setting Signature mode for it, while generating the key
setSignaturePaddings(SIGNATURE_PADDING_RSA_PKCS1)
This question already has answers here:
"Your app contains unsafe cryptographic encryption patterns" - How I can get rid of this warning?
(2 answers)
Closed 3 years ago.
I'm encrypting the password for firebase sign in, it's working well but I received a warning in google play console that your app contains unsafe cryptographic encryption patterns how can I get rid of it ??
I'm trying it on android studio.
public static class AESCrypt
{
private static final String ALGORITHM = "AES";
private static final String KEY = "1Hbfh667adfDEJ78";
public static String encrypt(String value) throws Exception
{
Key key = generateKey();
Cipher cipher = Cipher.getInstance(AESCrypt.ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key);
byte [] encryptedByteValue = cipher.doFinal(value.getBytes("utf-8"));
String encryptedValue64 = Base64.encodeToString(encryptedByteValue, Base64.DEFAULT);
return encryptedValue64;
}
public static String decrypt(String value) throws Exception
{
Key key = generateKey();
Cipher cipher = Cipher.getInstance(AESCrypt.ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decryptedValue64 = Base64.decode(value, Base64.DEFAULT);
byte [] decryptedByteValue = cipher.doFinal(decryptedValue64);
String decryptedValue = new String(decryptedByteValue,"utf-8");
return decryptedValue;
}
private static Key generateKey() throws Exception
{
Key key = new SecretKeySpec(AESCrypt.KEY.getBytes(),AESCrypt.ALGORITHM);
return key;
}
The main issues are that you use a cipher with no integrity and a hard coded cryptographic key. If you analyse your source with Find Security Bugs you get CIPHER_INTEGRITY and HARD_CODE_KEY warning:
The cipher does not provide data integrity [com.lloyds.keystorage.AESCrypt] At AESCrypt.java:[line 25] CIPHER_INTEGRITY
The cipher does not provide data integrity [com.lloyds.keystorage.AESCrypt] At AESCrypt.java:[line 15] CIPHER_INTEGRITY
Hard coded cryptographic key found [com.lloyds.keystorage.AESCrypt] At AESCrypt.java:[line 35] HARD_CODE_KEY
The solution is to use a cipher that includes a Hash based Message Authentication Code (HMAC) to sign the data:
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
And to store the secret key in separate configuration files or keystores.
Below is the whole class after a full refactoring:
import android.util.Base64
import static java.nio.charset.StandardCharsets.UTF_8;
import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class AESCrypt {
private static final String TRANSFORMATION = "AES/GCM/NoPadding";
public static String encrypt(String value) throws Exception {
Key key = generateKey();
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encryptedByteValue = cipher.doFinal(value.getBytes(UTF_8));
return Base64.encodeToString(encryptedByteValue, Base64.DEFAULT);
}
public static String decrypt(String value) throws Exception {
Key key = generateKey();
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decryptedValue64 = Base64.decode(value, Base64.DEFAULT);
byte[] decryptedByteValue = cipher.doFinal(decryptedValue64);
return new String(decryptedByteValue, UTF_8);
}
private static Key generateKey() {
return new SecretKeySpec(Configuration.getKey().getBytes(UTF_8), TRANSFORMATION);
}
}
I am generating a keypair using Java's KeyPairGenerator for use with JGit. However, JSch (the underlying SSH implementation for JGit) keeps giving me "invalid privatekey" errors when trying to use the generated private key.
Here is the stack trace:
Caught: org.eclipse.jgit.api.errors.TransportException: ssh://git#bitbucket.hostname/~wlaw/bitbucket_upgrade_test_repo.git: invalid privatekey: [B#4650a407
org.eclipse.jgit.api.errors.TransportException: ssh://git#bitbucket.hostname/~wlaw/bitbucket_upgrade_test_repo.git: invalid privatekey: [B#4650a407
at org.eclipse.jgit.api.FetchCommand.call(FetchCommand.java:254)
at org.eclipse.jgit.api.CloneCommand.fetch(CloneCommand.java:306)
at org.eclipse.jgit.api.CloneCommand.call(CloneCommand.java:200)
at org.eclipse.jgit.api.CloneCommand.call(CloneCommand.java:1)
at java_util_concurrent_Callable$call.call(Unknown Source)
at Test.run(Test.groovy:95)
Caused by: org.eclipse.jgit.errors.TransportException: ssh://git#bitbucket.hostname/~wlaw/bitbucket_upgrade_test_repo.git: invalid privatekey: [B#4650a407
at org.eclipse.jgit.transport.JschConfigSessionFactory.getSession(JschConfigSessionFactory.java:183)
at org.eclipse.jgit.transport.SshTransport.getSession(SshTransport.java:140)
at org.eclipse.jgit.transport.TransportGitSsh$SshFetchConnection.<init>(TransportGitSsh.java:280)
at org.eclipse.jgit.transport.TransportGitSsh.openFetch(TransportGitSsh.java:170)
at org.eclipse.jgit.transport.FetchProcess.executeImp(FetchProcess.java:137)
at org.eclipse.jgit.transport.FetchProcess.execute(FetchProcess.java:123)
at org.eclipse.jgit.transport.Transport.fetch(Transport.java:1271)
at org.eclipse.jgit.api.FetchCommand.call(FetchCommand.java:243)
... 5 more
Caused by: com.jcraft.jsch.JSchException: invalid privatekey: [B#4650a407
at com.jcraft.jsch.KeyPair.load(KeyPair.java:948)
at com.jcraft.jsch.IdentityFile.newInstance(IdentityFile.java:46)
at com.jcraft.jsch.JSch.addIdentity(JSch.java:442)
at Test$1.createDefaultJSch(Test.groovy:82)
at org.eclipse.jgit.transport.JschConfigSessionFactory.getJSch(JschConfigSessionFactory.java:335)
at org.eclipse.jgit.transport.JschConfigSessionFactory.createSession(JschConfigSessionFactory.java:293)
at org.eclipse.jgit.transport.JschConfigSessionFactory.createSession(JschConfigSessionFactory.java:200)
at org.eclipse.jgit.transport.JschConfigSessionFactory.getSession(JschConfigSessionFactory.java:130)
... 12 more
Here is my code:
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA")
keyGen.initialize(4096)
KeyPair pair = keyGen.generateKeyPair()
def pub = pair.public as RSAPublicKey
def priv = pair.private as RSAPrivateCrtKey
Base64.Encoder encoder = Base64.getEncoder();
def publicKeyText = "ssh-rsa " + encoder.encodeToString(keyBlob(pub.publicExponent, pub.modulus))
def id = bitbucket.post {
request.uri.path = "/rest/ssh/1.0/keys"
request.uri.query = [user: bitbucketUsername]
request.body = new JsonBuilder([text: publicKeyText]).toPrettyString()
response.success { FromServer fs, Object responseBody ->
responseBody.id
}
response.failure { FromServer fs, Object responseBody ->
println fs.statusCode
println fs.message
println fs.headers
println responseBody
null
}
}
def privateKeyText = "-----BEGIN RSA PRIVATE KEY-----\n" +
encoder.encodeToString(priv.getEncoded()) +
"\n-----END RSA PRIVATE KEY-----\n"
new File("priv").text = privateKeyText
new File("pub").text = publicKeyText
SshSessionFactory sshSessionFactory = new JschConfigSessionFactory() {
#Override
protected void configure(OpenSshConfig.Host hc, com.jcraft.jsch.Session session) {}
#Override
protected JSch createDefaultJSch(FS fs) throws JSchException {
JSch defaultJSch = super.createDefaultJSch(fs)
defaultJSch.addIdentity("test", privateKeyText.bytes, publicKeyText.bytes, null)
}
};
CloneCommand cloneCommand = Git.cloneRepository()
cloneCommand.setURI("ssh://git#$bitbucketHostPort/$project/${repo}.git")
cloneCommand.setTransportConfigCallback(new TransportConfigCallback() {
#Override
void configure(Transport transport) {
SshTransport sshTransport = (SshTransport) transport
sshTransport.setSshSessionFactory(sshSessionFactory)
}
})
cloneCommand.call()
I did some debugging in the JSch source code, and found that the library is getting an ArrayIndexOutOfBoundsException on line 228 in com.jcraft.jsch.KeyPairRSA.java.
Is it something I am doing wrong with formatting the keys for JSch? Or could this be a bug in Java's implementation of a KeyPair or perhaps JSch's implementation of parsing them?
Here is an example keypair that is generated by my code:
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDNPvFmy81wj3L4ndJzMcYFa9YctDzz0KvXyb9vg+UQ5622kyE255fwL4eatihL8/TrH1OOLQtSVjThLwWObx4fQ6bk25rJA0jS7G7CAfAQwbTY9JpNrcH5HHtiAhbUjEF/MXU6IlPNCmBMQPFh1eSa21aIdYie+KVgXQnUP4qN6ks1iR8XX4YHpg2KKhEoJtaVYGHp15EmpRvDYzsheqrcfyg4N5taGgG9/GzdfpeBWqCyJhrjgso85ARecGTpqCHqFNy46tXtIMR6FL36UDc/EpWifmf7oY4HVLa0DJpLq2BHmjRlUtiFFox1Jzk+shFiDZYwnCmdKnpCnlxFQ1Hv06XLgvcUx/0mkleh14Nme/b61pmJDO05v9zKho+9Q+lNgrTK+kOeC7I9PgUePyzWJteys/0MqENJxvM4g65/r9vzpcSvdEziSJ8Y3xI3qlzOa3Av1Jv5qIntgjEeAnth+AANdUP/GcpYbnCNp1QsjaZoFKFe2DcUTYM3CGzh0SFm9CeRfBV1phQ2+5gi1bH5ZiAfTNpksZz+SYIPyEsbaqNRcBk53htWfINShNVP7a/b/H7tyZs+zvMoHN2bZzsIMIUWO8Df+owpCK7ZT/EadDZzkzG2LUUUjm6aVsz2rjLFcvQtYOs0U/+suWhXNQ2dAW4psGLHkNb3NDHSzjzk7w==
-----BEGIN RSA PRIVATE KEY-----
MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQDNPvFmy81wj3L4ndJzMcYFa9YctDzz0KvXyb9vg+UQ5622kyE255fwL4eatihL8/TrH1OOLQtSVjThLwWObx4fQ6bk25rJA0jS7G7CAfAQwbTY9JpNrcH5HHtiAhbUjEF/MXU6IlPNCmBMQPFh1eSa21aIdYie+KVgXQnUP4qN6ks1iR8XX4YHpg2KKhEoJtaVYGHp15EmpRvDYzsheqrcfyg4N5taGgG9/GzdfpeBWqCyJhrjgso85ARecGTpqCHqFNy46tXtIMR6FL36UDc/EpWifmf7oY4HVLa0DJpLq2BHmjRlUtiFFox1Jzk+shFiDZYwnCmdKnpCnlxFQ1Hv06XLgvcUx/0mkleh14Nme/b61pmJDO05v9zKho+9Q+lNgrTK+kOeC7I9PgUePyzWJteys/0MqENJxvM4g65/r9vzpcSvdEziSJ8Y3xI3qlzOa3Av1Jv5qIntgjEeAnth+AANdUP/GcpYbnCNp1QsjaZoFKFe2DcUTYM3CGzh0SFm9CeRfBV1phQ2+5gi1bH5ZiAfTNpksZz+SYIPyEsbaqNRcBk53htWfINShNVP7a/b/H7tyZs+zvMoHN2bZzsIMIUWO8Df+owpCK7ZT/EadDZzkzG2LUUUjm6aVsz2rjLFcvQtYOs0U/+suWhXNQ2dAW4psGLHkNb3NDHSzjzk7wIDAQABAoICAFeJI83y1/DMzX0pWmtU7B69yji9yk02T0QeQG5gM18NYHJAt+bByXRf4Rbj37XdGzT4TFuT7IM2TyFHO7huvcsZwGFVI+Pdab7Dpc1KpEeRRf9N+01r8RG8ywaW24PVOc30mwmrQFBvv3hmLkzKu9AsAfD7J8SdSXMa2ylR3FcAeQkhLUh7rh8u/BFUNbMJNXXKAJiKHtb7jia7+KkjtyGJfe7UEIbSFrIfqZKh/h3mOCkixU8JJhXoLdDVYMSit6wtL6ISTiDvW7yxggDzG0zkMTt3bAPO+FM6Fx4dTeU99zcylmwsdDn2zvrcOrb5nR5Tqx2aTMlCJ5ioD7RerN+3YAhE1+cvrvZc5wa+aZruNMioTrxWzhc3iSoZHKKGE5VAnF/HkoR/lgCGVCcsWeNamdUjydD9H9Y/33S7Y0e+wLCNXOAmyE2jSMpHGEPwohlwyXrMvnKXoWX/LlNjhG8aWW8dWL6Lym3Z/eO3WBEe1Xccv9jd56h52rqvzW3MOpL320RcgqdLtgb7Ihz8twQdAyjaY81fJJtSnns/GBrbqAxO//EyWi8vBU82p4hl3tw8RAxGrx91LFPwv78ACvht8X8ogU4/c1B6rnI0n+Ofsvq9ZxQsATQAk1y83vPbTUNc+XJ8X/Jvxr/y1mp+8q9fIq2jHGUGJevBSW1+RBoZAoIBAQDzyhXuEiXtoBPMWew+ALUIJ5sW3JS+uShxq8KKo/a/V7OyrrBZTYmbjkxyxBlkKJUFA7xqwVXgnMkywA0EnrdE0TmmBwr7czZjT7Lp4PbhoZ73YJ/y31nuJJCGzkLeJKrtFaM2BdzPdqC86qeAIN9YHZnzyud+o6RkJlDje5hFv6cP5+JGu1OyhqNvFSyevKZLq5hGx6gkqSCVM65PhJELj4jwgI84E7pm9w7sZ5xN2X0W66dmElpN3OBj2VWlF6eiUNoIU3WyHwMn2+rrC8+YTGp9ByCR/+sHkM9mXQeT/3tjrBdXppRjy5EggcTW6T1KObnmOBgLDYLyxj4dFfXVAoIBAQDXhqUUFQarfK4jBgBcD3PzwyXtl9F6e4/IrdCwePjgRDuTNlcdUV/9HlfwNDEiVhd9ymcNwX/26W6VmEBAdec6czVVAY9fhZRz6Pp9DOH/7nJsln6Yz76ezOFeTJXm93dRLX/mkVM4qz4+JqPgll53IlYI9f6eqBZCfHJHj+LeCZDnDvKvF4M+LTpLR/fiF4/mVrBjrh6DuHwWPBnRCViKQyTkj8WCRRtRSWucZYplguCYN30iSH7Dv1MdnJGYie8dRDnDvV2G3dI666ugDVLZb48Rg+o3La3DzA7qEMQ6Lpy3abjyaaWOIz1Z/n3gQGWrqgeZpIZpnV04E5WS9X2zAoIBAH0iAmWjrRIuc1sV4PvmUwWvhpySdkr7MTY/amjNRm7qblNN9TixYuuUe8sAuuO9LNhZFZJaUGEtONyy1TvE198b4ZJF1S5B8e3Bz9zaWv5vffAOCauZV0i0Pfbj0lDB03ZD//VPxwo6IsE1VOqgdON+tjH7uR04k73QKP7KxtsuR2sTpAKYTpq5HxR6ct+7h0QZ/Nx/yN+gbBgJYfRw4B5l+20vH9Qx1CDbuS5A9GrFMr7cEJ2E2BNVR1wZByvpW2MmSvOxGx1la7I+4HLrKhBLUPGCAgbOrG3Ct6IcKDKgFU6Q255i45HhwElGMqn5KDt8K95udnDd65P/i4xUZE0CggEBALqThwixgwqlbqJHKbyIbBqTz5u1F9TubnSNc+Gxd9G9f81a92Mb9PrMb9gzdm2BFekBdOEFp996CQ9btBOZfcitv3eNWC6bFv6Yq2/h3SuPomK6jXGANkaGmnrl1ccSZ6pQty5ElES0ibeH/8oGolSD1vL+8aMrY8m+rbehqgYJRfWgjRpiQm1q/dH5xW9mcl42oZBJRYVGCbW95aN+cbWPlrp+c77oUFO4OX40sPBbsk5TivJIy+RtFmjGB4yDrAor6821euer07jKF9MAdb5hwvqotfN6ibi8SBT82sJ7Y5Or5D2Gk5lOjGgB1bpyRRGsqdOqB+oaHn7TBWMpPd0CggEAFPHds2f5CKjsNg9IkiA4yoCzfsjVhy9qiE/2BikA25JTc6nMfTfpWMzcDL3qnfhFGsFWz31Xf8MbZDMq0cCsMQhsgYPolU5N2AkWvAeqSbwMz9zIDiPeND/Ql4sOyicPd6LJrT3UTRWoY3+p4wo73rpOXM4Ju3u++sCeERTulghgGZoJBSIT+8H7pKa7cFchATvBKZQTUnOZEhqzQN4R2wZ3j5ujG8rGjfRHDRL8OPiNRRv/L/oHxGnhB4Rfbc4ba0zNx4zy6d+Em6H8wX72WHhz5eVs2xQR+EIBtxDVlmvdpGkvCtUhS1227yiiL+wqkfNz3UnTSjGy3eHNRGAsVg==
-----END RSA PRIVATE KEY-----
You need to write the private key in PEM format.
For that you need BouncyCastle library.
For an example see:
Java generate RSA key pair and convert to PEM
I'm writing PGP server to generate keys for users.
I want to sign any generated PGP public key with my private key in Java with Bouncy Castle, to make it trusted for my users.
I have no problems with generating key pair - it works perfect.
I tried to sign by gpg --sign-key command line and it works good.
But I can't get the same in Java. I tried many solutions like this: java sign public pgp key with bouncycastle
and DirectKeySignature class from BC examples package, but nothing works for my.
Key is signed but gpg --check-sigs tell that signature is incorrect:
gpg --check-sigs "Adrian (test) <al#p-c.pl>"
pub 4096R/9D5D4AB8 2018-06-20
sig- E9798A8A 2018-08-04 Test (test) <test#sample.com>
uid Adrian (test) <al#p-c.pl>
sig! 9D5D4AB8 2018-06-20 Adrian (test) <al#p-c.pl>
1 incorrect signature
Source code in two versions:
version 1:
public void signKey(String id, PGPSecretKey mySecretKey, PGPPublicKey publicKeyToBeSigned, char[] passPhrase, OutputStream out) throws PGPException, IOException {
PGPPrivateKey pgpPrivKey = mySecretKey.extractPrivateKey(
new JcePBESecretKeyDecryptorBuilder().setProvider(provider).build(passPhrase));
PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(
new JcaPGPContentSignerBuilder(mySecretKey.getPublicKey().getAlgorithm(), PGPUtil.SHA1));
signatureGenerator.init(PGPSignature.DIRECT_KEY, pgpPrivKey);
PGPSignature signature = signatureGenerator.generateCertification(id, publicKeyToBeSigned);
PGPPublicKey result = PGPPublicKey.addCertification(publicKeyToBeSigned, signature);
out = new ArmoredOutputStream(out);
result.encode(out);
out.close();
}
version 2 (baset on org.bouncycastle.openpgp.examples.DirectKeySignature):
public void signPublicKey(PGPSecretKey secretKey, String secretKeyPass, PGPPublicKey keyToBeSigned, String notationName, String notationValue, OutputStream out) throws Exception {
PGPPrivateKey pgpPrivKey = secretKey.extractPrivateKey(
new JcePBESecretKeyDecryptorBuilder().setProvider("BC").build(secretKeyPass.toCharArray()));
PGPSignatureGenerator sGen = new PGPSignatureGenerator(
new JcaPGPContentSignerBuilder(secretKey.getPublicKey().getAlgorithm(), PGPUtil.SHA1).setProvider("BC"));
sGen.init(PGPSignature.DIRECT_KEY, pgpPrivKey);
PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
boolean isHumanReadable = true;
spGen.setNotationData(true, isHumanReadable, notationName, notationValue);
PGPSignatureSubpacketVector packetVector = spGen.generate();
sGen.setHashedSubpackets(packetVector);
PGPPublicKey result = PGPPublicKey.addCertification(keyToBeSigned, sGen.generate());
out = new ArmoredOutputStream(out);
result.encode(out);
out.close();
}
Test:
#Test
public void signKey() throws Exception {
FileInputStream in = new FileInputStream("src/test/resources/secret.dat");
PgpServiceImpl pgp = new PgpServiceImpl();
PGPSecretKey pgpSecretKey = pgp.readSecretKey(in, "..........".toCharArray());
PGPPublicKey pubKey = pgp.readPublicKey(new FileInputStream("src/test/resources/pub_other.dat"));
ByteArrayOutputStream res = new ByteArrayOutputStream();
pgp.signPublicKey(pgpSecretKey, "..........", pubKey, "Test (test) <test#sample.com>", "Adrian (test) <al#p-c.pl>", res);
System.out.println(new String(res.toByteArray()));
}
result:
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: BCPG v1.60
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
snGdpaUOpLJZRe2zI/i59UIHi1OoKERxYw==
=9lxJ
-----END PGP PUBLIC KEY BLOCK-----
this works perfectly:
public void signPublicKey(PGPSecretKey secretKey, char[] passPhrase, PGPPublicKey keyToBeSigned, OutputStream out) throws PGPException, IOException {
PGPPrivateKey pgpPrivKey = secretKey.extractPrivateKey(
new JcePBESecretKeyDecryptorBuilder().setProvider( provider )
.build(passPhrase));
PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(
new JcaPGPContentSignerBuilder( secretKey.getPublicKey().getAlgorithm(), PGPUtil.SHA1 ) );
signatureGenerator.init( PGPSignature.DEFAULT_CERTIFICATION, pgpPrivKey );
Iterator<String> ids = keyToBeSigned.getUserIDs();
if(!ids.hasNext()) throw new IllegalArgumentException("klucz nie posiada żadnego User ID");
String id = ids.next();
PGPSignature signature = signatureGenerator.generateCertification(id, keyToBeSigned);
PGPPublicKey newKey = PGPPublicKey.addCertification(keyToBeSigned, id, signature);
out = new ArmoredOutputStream(out);
newKey.encode(out);
out.close();
}
I am looking for a procedure of enrolling a certificate.
I have searched a lot but didn't find a good answer. Till now I get that firstly I have to generate a Key store (For creating a public key and a private key) then private key should be kept private and public key is sent with other information (like name and organization) to the CA. Then the CA will generate something and give me back something which contains the public key and information.
What does the CA generate? What is a P12 file and what does a .cer file contain?
The general procedure to issue certificates in a Public Key Infrastructure is more or less the following:
the client generates a key pair, private and public
the client generates a CSR (Certificate Signing Request) including attributes like Common Name and the Public Key. Signs it with the private key and sends it to the server
The server builds the X509 Certificate with the CSR data, signs it with the CA private key and returns the X509 to client
the client stores the private key and the certificate in a KeyStore
What CA generate?
The x509 certificate
What is P12 file
A file in PKCS#12 format (.pfx or .p12) containing a key store
what is .cer file contain
The public part of the certificate (not private key) in DER or PEM format
EDITED - CSR generation on Android
Gradle dependencies
compile 'com.madgag.spongycastle:core:1.51.0.0'
compile 'com.madgag.spongycastle:pkix:1.51.0.0'
Generate KeyPair and CSR
//Generate KeyPair
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(KEY_SIZE, new SecureRandom());
KeyPair keyPair = keyGen.generateKeyPair();
//Generate CSR in PKCS#10 format encoded in DER
PKCS10CertificationRequest csr = CsrHelper.generateCSR(keyPair, commonname);
byte CSRder[] = csr.getEncoded();
Utilities
public class CsrHelper {
private final static String DEFAULT_SIGNATURE_ALGORITHM = "SHA256withRSA";
private final static String CN_PATTERN = "CN=%s, O=Aralink, OU=OrgUnit";
private static class JCESigner implements ContentSigner {
private static Map<String, AlgorithmIdentifier> ALGOS = new HashMap<String, AlgorithmIdentifier>();
static {
ALGOS.put("SHA256withRSA".toLowerCase(), new AlgorithmIdentifier(
new ASN1ObjectIdentifier("1.2.840.113549.1.1.11")));
ALGOS.put("SHA1withRSA".toLowerCase(), new AlgorithmIdentifier(
new ASN1ObjectIdentifier("1.2.840.113549.1.1.5")));
}
private String mAlgo;
private Signature signature;
private ByteArrayOutputStream outputStream;
public JCESigner(PrivateKey privateKey, String sigAlgo) {
//Utils.throwIfNull(privateKey, sigAlgo);
mAlgo = sigAlgo.toLowerCase();
try {
this.outputStream = new ByteArrayOutputStream();
this.signature = Signature.getInstance(sigAlgo);
this.signature.initSign(privateKey);
} catch (GeneralSecurityException gse) {
throw new IllegalArgumentException(gse.getMessage());
}
}
#Override
public AlgorithmIdentifier getAlgorithmIdentifier() {
AlgorithmIdentifier id = ALGOS.get(mAlgo);
if (id == null) {
throw new IllegalArgumentException("Does not support algo: " +
mAlgo);
}
return id;
}
#Override
public OutputStream getOutputStream() {
return outputStream;
}
#Override
public byte[] getSignature() {
try {
signature.update(outputStream.toByteArray());
return signature.sign();
} catch (GeneralSecurityException gse) {
gse.printStackTrace();
return null;
}
}
}
//Create the certificate signing request (CSR) from private and public keys
public static PKCS10CertificationRequest generateCSR(KeyPair keyPair, String cn) throws IOException,
OperatorCreationException {
String principal = String.format(CN_PATTERN, cn);
ContentSigner signer = new JCESigner (keyPair.getPrivate(),DEFAULT_SIGNATURE_ALGORITHM);
PKCS10CertificationRequestBuilder csrBuilder = new JcaPKCS10CertificationRequestBuilder(
new X500Name(principal), keyPair.getPublic());
ExtensionsGenerator extensionsGenerator = new ExtensionsGenerator();
extensionsGenerator.addExtension(Extension.basicConstraints, true, new BasicConstraints(
true));
csrBuilder.addAttribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest,
extensionsGenerator.generate());
PKCS10CertificationRequest csr = csrBuilder.build(signer);
return csr;
}
}
To add on to pedrofb's answer you can also use SpongyCastle's JcaContentSignerBuilder instead of JCESigner which will condense your code considerably.
Utilities:
private final static String CN_PATTERN = "CN=%s, O=Aralink, OU=OrgUnit";
//Create the certificate signing request (CSR) from private and public keys
public static PKCS10CertificationRequest generateCSR(KeyPair keyPair, String cn) throws IOException, OperatorCreationException {
String principal = String.format(CN_PATTERN, cn);
ContentSigner signer = new JcaContentSignerBuilder(DEFAULT_RSA_SIGNATURE_ALGORITHM).build(keyPair.getPrivate());
PKCS10CertificationRequestBuilder csrBuilder = new JcaPKCS10CertificationRequestBuilder(
new X500Name(principal), keyPair.getPublic());
ExtensionsGenerator extensionsGenerator = new ExtensionsGenerator();
extensionsGenerator.addExtension(Extension.basicConstraints, true, new BasicConstraints(
true));
csrBuilder.addAttribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest,
extensionsGenerator.generate());
PKCS10CertificationRequest csr = csrBuilder.build(signer);
return csr;
}
}