Page tree
Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Current »

Bouncy Castle – библиотека с открытым исходным кодом предоставляющая API над криптографическими операциями. Сейчас эта библиотека существует для двух языков – Java и С# и по сути является аналогом OpenSSL в них.

Библиотека Bouncy Castle также предоставляет возможность по работе с токенами. Это возможно за счет реализации классов, реализующих примитивные криптографические операции (шифрование, взятие сырой подписи, хеширование и т.д.), и передаче их библиотеке Bouncy Castle. Пример реализации таких примитивных классов, можно найти в Rutoken SDK в директории /sdk/java/samples/pkcs11/src/ru/rutoken/samples/pkcs11/bouncycastle/bcprimitives/.


Например, для реализации примитива получения хеша нужно реализовать функции абстрактного класса DigestCalculator. Это может выглядеть так:

GostDigestCalculator
package ru.rutoken.samples.pkcs11.bouncycastle.bcprimitives;

import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.operator.DigestCalculator;
import ru.rutoken.samples.pkcs11.Pkcs11Exception;
import ru.rutoken.samples.pkcs11.bouncycastle.pkcs11operations.Pkcs11GostDigester;

import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.util.Objects;

class GostDigestCalculator implements DigestCalculator {
    private final Pkcs11GostDigester mPkcs11GostDigester;
    private final ByteArrayOutputStream mStream = new ByteArrayOutputStream();

    GostDigestCalculator(Pkcs11GostDigester pkcs11GostDigester) {
        mPkcs11GostDigester = Objects.requireNonNull(pkcs11GostDigester);
    }

    @Override
    public AlgorithmIdentifier getAlgorithmIdentifier() {
        return mPkcs11GostDigester.getDigestAlgorithm().getAlgorithmIdentifier();
    }

    @Override
    public byte[] getDigest() {
        byte[] data = mStream.toByteArray();
        try {
            byte[] digestedData = mPkcs11GostDigester.digest(data);
            mStream.reset();
            return digestedData;
        } catch (Pkcs11Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public OutputStream getOutputStream() {
        return mStream;
    }
}


Этот класс использует удобный класс-обертку Pkcs11GostDigester над PKCS#11 функциями для получения хеша. Детали реализации можно посмотреть в примерах  sdk:

Pkcs11GostDigester
package ru.rutoken.samples.pkcs11.bouncycastle.pkcs11operations;

import com.sun.jna.Memory;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.NativeLongByReference;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import ru.rutoken.pkcs11jna.CK_MECHANISM;
import ru.rutoken.pkcs11jna.Pkcs11;
import ru.rutoken.pkcs11jna.RtPkcs11Constants;
import ru.rutoken.samples.Constants;
import ru.rutoken.samples.pkcs11.Pkcs11Exception;
import ru.rutoken.samples.pkcs11.RtPkcs11Library;

public class Pkcs11GostDigester {
    private final DigestAlgorithm mDigestAlgorithm;
    private final long mSessionHandle;

    public Pkcs11GostDigester(DigestAlgorithm digestAlgorithm, long sessionHandle) {
        mDigestAlgorithm = digestAlgorithm;
        mSessionHandle = sessionHandle;
    }

    public DigestAlgorithm getDigestAlgorithm() {
        return mDigestAlgorithm;
    }

    public byte[] digest(byte[] data) throws Pkcs11Exception {
        final Pkcs11 pkcs11 = RtPkcs11Library.getPkcs11Interface();
        Pointer parameter = new Memory(mDigestAlgorithm.getAlgorithmParamset().length);
        parameter.write(0, mDigestAlgorithm.getAlgorithmParamset(), 0, mDigestAlgorithm.getAlgorithmParamset().length);

        // Pass null as parameter and 0 as parameter length if you want to perform hardware digest
        final CK_MECHANISM mechanism = new CK_MECHANISM(new NativeLong(mDigestAlgorithm.getPkcsMechanism()), parameter, new NativeLong(mDigestAlgorithm.getAlgorithmParamset().length));
        NativeLong rv = pkcs11.C_DigestInit(new NativeLong(mSessionHandle), mechanism);
        Pkcs11Exception.throwIfNotOk("C_DigestInit failed", rv);

        final NativeLongByReference count = new NativeLongByReference();
        rv = pkcs11.C_Digest(new NativeLong(mSessionHandle), data, new NativeLong(data.length), null, count);
        Pkcs11Exception.throwIfNotOk("C_Digest failed", rv);

        final byte[] digest = new byte[count.getValue().intValue()];
        rv = pkcs11.C_Digest(new NativeLong(mSessionHandle), data, new NativeLong(data.length), digest, count);
        Pkcs11Exception.throwIfNotOk("C_Digest failed", rv);

        return digest;
    }

    public enum DigestAlgorithm {
        GOSTR3411_1994(RtPkcs11Constants.CKM_GOSTR3411, new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3411), Constants.ATTR_GOSTR3411_1994),
        GOSTR3411_2012_256(RtPkcs11Constants.CKM_GOSTR3411_12_256, new AlgorithmIdentifier(RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256), Constants.ATTR_GOSTR3411_2012_256),
        GOSTR3411_2012_512(RtPkcs11Constants.CKM_GOSTR3411_12_512, new AlgorithmIdentifier(RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512), Constants.ATTR_GOSTR3411_2012_512);

        private final long mPkcsMechanism;
        private final AlgorithmIdentifier mAlgorithmIdentifier;
        private final byte[] mParamset;

        DigestAlgorithm(long pkcsMechanism, AlgorithmIdentifier algorithmIdentifier, byte[] paramset) {
            mPkcsMechanism = pkcsMechanism;
            mAlgorithmIdentifier = algorithmIdentifier;
            mParamset = paramset;
        }

        public long getPkcsMechanism() {
            return mPkcsMechanism;
        }

        public AlgorithmIdentifier getAlgorithmIdentifier() {
            return mAlgorithmIdentifier;
        }

        public byte[] getAlgorithmParamset() {
            return mParamset;
        }
    }
}


Полученный примитив можно использовать везде, где требуется объект с интерфейсом DigestCalculator. В своем приложении вы можете использовать готовые реализованные примитивы из нашего SDK и дополнять их.

  • No labels