Use a custom EdDsaAuthenticationContentSignerBuilder for signing with
EdDSA, since EdDSA expects the raw data instead of a hash
This commit is contained in:
parent
2e3649100c
commit
f70b10d548
|
@ -26,6 +26,7 @@ import java.security.interfaces.RSAPrivateCrtKey;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
|
||||||
import org.bouncycastle.bcpg.S2K;
|
import org.bouncycastle.bcpg.S2K;
|
||||||
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
|
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
|
||||||
import org.bouncycastle.openpgp.AuthenticationSignatureGenerator;
|
import org.bouncycastle.openpgp.AuthenticationSignatureGenerator;
|
||||||
|
@ -37,13 +38,7 @@ import org.bouncycastle.openpgp.PGPSignatureGenerator;
|
||||||
import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator;
|
import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator;
|
||||||
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
|
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
|
||||||
import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder;
|
import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder;
|
||||||
import org.bouncycastle.openpgp.operator.jcajce.CachingDataDecryptorFactory;
|
import org.bouncycastle.openpgp.operator.jcajce.*;
|
||||||
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
|
|
||||||
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyConverter;
|
|
||||||
import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
|
|
||||||
import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder;
|
|
||||||
import org.bouncycastle.openpgp.operator.jcajce.NfcSyncPGPContentSignerBuilder;
|
|
||||||
import org.bouncycastle.openpgp.operator.jcajce.SessionKeySecretKeyDecryptorBuilder;
|
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||||
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
||||||
|
@ -219,8 +214,7 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private PGPContentSignerBuilder getContentSignerBuilder(int hashAlgo,
|
private PGPContentSignerBuilder getContentSignerBuilder(int hashAlgo, Map<ByteBuffer, byte[]> signedHashes) {
|
||||||
Map<ByteBuffer,byte[]> signedHashes) {
|
|
||||||
if (mPrivateKeyState == PRIVATE_KEY_STATE_DIVERT_TO_CARD) {
|
if (mPrivateKeyState == PRIVATE_KEY_STATE_DIVERT_TO_CARD) {
|
||||||
// use synchronous "NFC based" SignerBuilder
|
// use synchronous "NFC based" SignerBuilder
|
||||||
return new NfcSyncPGPContentSignerBuilder(
|
return new NfcSyncPGPContentSignerBuilder(
|
||||||
|
@ -253,6 +247,20 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private PGPContentSignerBuilder getAuthenticationContentSignerBuilder(int hashAlgorithm, Map<ByteBuffer,
|
||||||
|
byte[]> signedHashes) {
|
||||||
|
if (getAlgorithm() == PublicKeyAlgorithmTags.EDDSA) {
|
||||||
|
// content signer feeding the input directly into the signature engine,
|
||||||
|
// since EdDSA hashes the input anyway
|
||||||
|
return new EdDsaAuthenticationContentSignerBuilder(
|
||||||
|
mSecretKey.getPublicKey().getAlgorithm(), hashAlgorithm)
|
||||||
|
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||||
|
} else {
|
||||||
|
return getContentSignerBuilder(hashAlgorithm, signedHashes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public AuthenticationSignatureGenerator getAuthenticationSignatureGenerator(int hashAlgorithm,
|
public AuthenticationSignatureGenerator getAuthenticationSignatureGenerator(int hashAlgorithm,
|
||||||
Map<ByteBuffer, byte[]> signedHashes)
|
Map<ByteBuffer, byte[]> signedHashes)
|
||||||
throws PgpGeneralException {
|
throws PgpGeneralException {
|
||||||
|
@ -260,10 +268,12 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
|
||||||
throw new PrivateKeyNotUnlockedException();
|
throw new PrivateKeyNotUnlockedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
PGPContentSignerBuilder contentSignerBuilder = getContentSignerBuilder(hashAlgorithm, signedHashes);
|
PGPContentSignerBuilder contentSignerBuilder =
|
||||||
|
getAuthenticationContentSignerBuilder(hashAlgorithm, signedHashes);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
AuthenticationSignatureGenerator signatureGenerator = new AuthenticationSignatureGenerator(contentSignerBuilder);
|
AuthenticationSignatureGenerator signatureGenerator =
|
||||||
|
new AuthenticationSignatureGenerator(contentSignerBuilder);
|
||||||
signatureGenerator.init(PGPSignature.BINARY_DOCUMENT, mPrivateKey);
|
signatureGenerator.init(PGPSignature.BINARY_DOCUMENT, mPrivateKey);
|
||||||
|
|
||||||
return signatureGenerator;
|
return signatureGenerator;
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
package org.bouncycastle.openpgp.operator.jcajce;
|
||||||
|
|
||||||
|
import org.bouncycastle.jcajce.provider.asymmetric.eddsa.EdDSAEngine;
|
||||||
|
import org.bouncycastle.jcajce.provider.asymmetric.eddsa.spec.EdDSANamedCurveTable;
|
||||||
|
import org.bouncycastle.jcajce.provider.asymmetric.eddsa.spec.EdDSAParameterSpec;
|
||||||
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
|
import org.bouncycastle.openpgp.PGPPrivateKey;
|
||||||
|
import org.bouncycastle.openpgp.PGPRuntimeOperationException;
|
||||||
|
import org.bouncycastle.openpgp.operator.PGPContentSigner;
|
||||||
|
import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.security.*;
|
||||||
|
|
||||||
|
public class EdDsaAuthenticationContentSignerBuilder implements PGPContentSignerBuilder {
|
||||||
|
private JcaPGPKeyConverter keyConverter = new JcaPGPKeyConverter();
|
||||||
|
private int hashAlgorithm;
|
||||||
|
private int keyAlgorithm;
|
||||||
|
|
||||||
|
public EdDsaAuthenticationContentSignerBuilder(int keyAlgorithm, int hashAlgorithm) {
|
||||||
|
this.keyAlgorithm = keyAlgorithm;
|
||||||
|
this.hashAlgorithm = hashAlgorithm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EdDsaAuthenticationContentSignerBuilder setProvider(Provider provider) {
|
||||||
|
keyConverter.setProvider(provider);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EdDsaAuthenticationContentSignerBuilder setProvider(String providerName) {
|
||||||
|
keyConverter.setProvider(providerName);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Signature createSignature() throws NoSuchAlgorithmException {
|
||||||
|
EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName("Ed25519");
|
||||||
|
return new EdDSAEngine(MessageDigest.getInstance(spec.getHashAlgorithm()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public PGPContentSigner build(final int signatureType, final long keyID, final PrivateKey privateKey)
|
||||||
|
throws PGPException {
|
||||||
|
Signature signatureEdDsa;
|
||||||
|
try {
|
||||||
|
signatureEdDsa = createSignature();
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
throw new PGPException("unable to create Signature.", e);
|
||||||
|
}
|
||||||
|
final Signature signature = signatureEdDsa;
|
||||||
|
|
||||||
|
final ByteArrayOutputStream dataOutputStream = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
try {
|
||||||
|
signature.initSign(privateKey);
|
||||||
|
} catch (InvalidKeyException e) {
|
||||||
|
throw new PGPException("invalid key.", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new PGPContentSigner() {
|
||||||
|
public int getType() {
|
||||||
|
return signatureType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getHashAlgorithm() {
|
||||||
|
return hashAlgorithm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getKeyAlgorithm() {
|
||||||
|
return keyAlgorithm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getKeyID() {
|
||||||
|
return keyID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OutputStream getOutputStream() {
|
||||||
|
return new SignatureOutputStream(signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getSignature() {
|
||||||
|
try {
|
||||||
|
return signature.sign();
|
||||||
|
} catch (SignatureException e) {
|
||||||
|
throw new PGPRuntimeOperationException("Unable to create signature: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getDigest() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public PGPContentSigner build(final int signatureType, PGPPrivateKey privateKey) throws PGPException {
|
||||||
|
if (privateKey instanceof JcaPGPPrivateKey) {
|
||||||
|
return build(signatureType, privateKey.getKeyID(), ((JcaPGPPrivateKey) privateKey).getPrivateKey());
|
||||||
|
} else {
|
||||||
|
return build(signatureType, privateKey.getKeyID(), keyConverter.getPrivateKey(privateKey));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue