Use a custom EdDsaAuthenticationContentSignerBuilder for signing with

EdDSA, since EdDSA expects the raw data instead of a hash
This commit is contained in:
Christian Hagau 2017-11-13 00:00:00 +00:00
parent 2e3649100c
commit f70b10d548
2 changed files with 122 additions and 11 deletions

View file

@ -26,6 +26,7 @@ import java.security.interfaces.RSAPrivateCrtKey;
import java.util.Date;
import java.util.Map;
import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
import org.bouncycastle.bcpg.S2K;
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.bouncycastle.openpgp.AuthenticationSignatureGenerator;
@ -37,13 +38,7 @@ import org.bouncycastle.openpgp.PGPSignatureGenerator;
import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator;
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder;
import org.bouncycastle.openpgp.operator.jcajce.CachingDataDecryptorFactory;
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.bouncycastle.openpgp.operator.jcajce.*;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
@ -219,8 +214,7 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
return true;
}
private PGPContentSignerBuilder getContentSignerBuilder(int hashAlgo,
Map<ByteBuffer,byte[]> signedHashes) {
private PGPContentSignerBuilder getContentSignerBuilder(int hashAlgo, Map<ByteBuffer, byte[]> signedHashes) {
if (mPrivateKeyState == PRIVATE_KEY_STATE_DIVERT_TO_CARD) {
// use synchronous "NFC based" SignerBuilder
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,
Map<ByteBuffer, byte[]> signedHashes)
throws PgpGeneralException {
@ -260,10 +268,12 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
throw new PrivateKeyNotUnlockedException();
}
PGPContentSignerBuilder contentSignerBuilder = getContentSignerBuilder(hashAlgorithm, signedHashes);
PGPContentSignerBuilder contentSignerBuilder =
getAuthenticationContentSignerBuilder(hashAlgorithm, signedHashes);
try {
AuthenticationSignatureGenerator signatureGenerator = new AuthenticationSignatureGenerator(contentSignerBuilder);
AuthenticationSignatureGenerator signatureGenerator =
new AuthenticationSignatureGenerator(contentSignerBuilder);
signatureGenerator.init(PGPSignature.BINARY_DOCUMENT, mPrivateKey);
return signatureGenerator;

View file

@ -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));
}
}
}