org.xipki.security.DSAPlainDigestSigner Maven / Gradle / Ivy
/*
*
* Copyright (c) 2013 - 2019 Lijun Liao
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.xipki.security;
import java.io.IOException;
import java.math.BigInteger;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.DSA;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.Signer;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.xipki.security.util.SignerUtil;
import org.xipki.util.Args;
/**
* Plain-DSA signer. The signature is not encoded as ASN.1 structure, but just the
* concatenation of two integer (r and s) in format of byte array.
*
* @author Lijun Liao
* @since 2.0.0
*/
// CHECKSTYLE:SKIP
public class DSAPlainDigestSigner implements Signer {
private final Digest digest;
private final DSA dsaSigner;
private boolean forSigning;
private int keyBitLen;
public DSAPlainDigestSigner(DSA signer, Digest digest) {
this.digest = digest;
this.dsaSigner = signer;
}
@Override
public void init(boolean forSigning, CipherParameters parameters) {
this.forSigning = forSigning;
AsymmetricKeyParameter param = (parameters instanceof ParametersWithRandom)
? (AsymmetricKeyParameter) ((ParametersWithRandom) parameters).getParameters()
: (AsymmetricKeyParameter) parameters;
Args.notNull(param, "param");
if (param instanceof ECPublicKeyParameters) {
keyBitLen = ((ECPublicKeyParameters) param).getParameters().getCurve().getFieldSize();
} else if (param instanceof ECPrivateKeyParameters) {
keyBitLen = ((ECPrivateKeyParameters) param).getParameters().getCurve().getFieldSize();
} else if (param instanceof DSAPublicKeyParameters) {
keyBitLen = ((DSAPublicKeyParameters) param).getParameters().getQ().bitLength();
} else if (param instanceof DSAPrivateKeyParameters) {
keyBitLen = ((DSAPrivateKeyParameters) param).getParameters().getQ().bitLength();
} else {
throw new IllegalArgumentException("unknown parameters: " + param.getClass().getName());
}
if (forSigning && !param.isPrivate()) {
throw new IllegalArgumentException("Signing Requires Private Key.");
}
if (!forSigning && param.isPrivate()) {
throw new IllegalArgumentException("Verification Requires Public Key.");
}
reset();
dsaSigner.init(forSigning, parameters);
}
@Override
public void update(byte input) {
digest.update(input);
}
@Override
public void update(byte[] input, int inOff, int length) {
digest.update(input, inOff, length);
}
@Override
public byte[] generateSignature() {
if (!forSigning) {
throw new IllegalStateException("DSADigestSigner not initialized for signature generation.");
}
byte[] hash = new byte[digest.getDigestSize()];
digest.doFinal(hash, 0);
BigInteger[] sig = dsaSigner.generateSignature(hash);
try {
return SignerUtil.dsaSigToPlain(sig[0], sig[1], keyBitLen);
} catch (XiSecurityException ex) {
throw new IllegalStateException("unable to encode signature");
}
}
@Override
public boolean verifySignature(byte[] signature) {
if (forSigning) {
throw new IllegalStateException("DSADigestSigner not initialised for verification");
}
byte[] hash = new byte[digest.getDigestSize()];
digest.doFinal(hash, 0);
try {
BigInteger[] sig = decode(signature);
return dsaSigner.verifySignature(hash, sig[0], sig[1]);
} catch (IOException ex) {
return false;
}
}
@Override
public void reset() {
digest.reset();
}
private BigInteger[] decode(byte[] encoding) throws IOException {
int blockSize = (keyBitLen + 7) / 8;
if (encoding.length != 2 * blockSize) {
throw new IOException("invalid length of signature");
}
BigInteger[] ret = new BigInteger[2];
byte[] buffer = new byte[blockSize + 1];
System.arraycopy(encoding, 0, buffer, 1, blockSize);
ret[0] = new BigInteger(buffer);
buffer = new byte[blockSize + 1];
System.arraycopy(encoding, blockSize, buffer, 1, blockSize);
ret[1] = new BigInteger(buffer);
return ret;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy