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.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;
|
||||
|
|
|
@ -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