All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xipki.security.pkcs12.DSAPlainDigestSigner Maven / Gradle / Ivy

/*
 *
 * Copyright (c) 2013 - 2017 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.pkcs12;

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.common.util.ParamUtil;
import org.xipki.security.exception.XiSecurityException;
import org.xipki.security.util.SignerUtil;

/**
 * @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(final DSA signer, final Digest digest) {
        this.digest = digest;
        this.dsaSigner = signer;
    }

    @Override
    public void init(final boolean forSigning, final CipherParameters parameters) {
        this.forSigning = forSigning;

        AsymmetricKeyParameter param;

        if (parameters instanceof ParametersWithRandom) {
            param = (AsymmetricKeyParameter) ((ParametersWithRandom) parameters).getParameters();
        } else {
            param = (AsymmetricKeyParameter) parameters;
        }

        ParamUtil.requireNonNull("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(final byte input) {
        digest.update(input);
    }

    @Override
    public void update(final byte[] input, final int inOff, final 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.convertDSASigToPlain(sig[0], sig[1], keyBitLen);
        } catch (XiSecurityException ex) {
            throw new IllegalStateException("unable to encode signature");
        }
    }

    @Override
    public boolean verifySignature(final 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(final 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