
Escape from Crypto Pro. GOST 34.10-2012 edition
On Habré there is a magnificent article " Escape from Crypto Pro. Director's version, SMEV-edition ", but the year 2019 came and all the CAs began to issue digital signatures in accordance with GOST 34.10-2012 instead of GOST 34.10-2001.
Under the cut, a story about how you can modify your software on Bouncy Castle to support working with keys for new guests.

I don’t know anything about the legal intricacies of signing documents through Bouncy Castle and other cryptographic information protection systems and I’m not ready to communicate. Before using the code in production, consult with a lawyer.
Why is this even necessary? well written original article. I will not repeat myself.

All CAs known to me issue keys with certificates on similar tokens. The cryptoPro container with the private key and certificate is written on the token. When exporting a key through CryptoPro CSP, it is exported to a special “CryptoPro pfx” that is not compatible with anything.
Requests to issue a key in a standard pfx or any other typical CA container are ignored.
If anyone knows the CA issuing signatures in standard containers, share the coordinates in the comments. Good people are not ashamed to promote.
To convert the CryptoPro container to standard pfx, we, as in the original article, will use P12FromGostCSP. Old hacked versions do not work with keys for 2012 Gost. We go to the authors website and buy a new one.
So we got the standard pfx with the key and certificate.
Bouncy Castle update We update Bouncy Castle
to 1.60 Older versions may not support GOST 2012 algorithms.
Initializing Bouncy Castle
Pfx parsing
Aliases must be changed. The P12FromGostCSP utility always sets the same alias “csp_exported” and there will be problems processing the second key.
For convenience, the key from pfx must be loaded into the standard Java KeyStore and then work only with it.
Download KeyStore
Saving a key with a certificate in KeyStore
Download keys and certificates from KeyStore
File signature
There is a JcaContentSignerBuilder option ("GOST3411WITHECGOST3410-2012-512") for 512 bit keys. My CAs issue 256 bit ones without asking anything and ignore clarifying questions.
Signature Verification
Signature verification is completely similar to the 2001 GOST verification. You can not change anything.
As a result of all the above actions, we got a relatively easy way to get rid of the heavy load of Crypto Pro in 2019.
Under the cut, a story about how you can modify your software on Bouncy Castle to support working with keys for new guests.

Disclaimer
I don’t know anything about the legal intricacies of signing documents through Bouncy Castle and other cryptographic information protection systems and I’m not ready to communicate. Before using the code in production, consult with a lawyer.
Why is this even necessary? well written original article. I will not repeat myself.
Obtaining a key from the Token

All CAs known to me issue keys with certificates on similar tokens. The cryptoPro container with the private key and certificate is written on the token. When exporting a key through CryptoPro CSP, it is exported to a special “CryptoPro pfx” that is not compatible with anything.
Requests to issue a key in a standard pfx or any other typical CA container are ignored.
If anyone knows the CA issuing signatures in standard containers, share the coordinates in the comments. Good people are not ashamed to promote.
To convert the CryptoPro container to standard pfx, we, as in the original article, will use P12FromGostCSP. Old hacked versions do not work with keys for 2012 Gost. We go to the authors website and buy a new one.
So we got the standard pfx with the key and certificate.
Bouncy Castle update We update Bouncy Castle
to 1.60 Older versions may not support GOST 2012 algorithms.
org.bouncycastle bcprov-jdk15on 1.60 org.bouncycastle bcpkix-jdk15on 1.60
Initializing Bouncy Castle
static {
BouncyCastleProvider bcProvider = new BouncyCastleProvider();
String name = bcProvider.getName();
Security.removeProvider(name); // remove old instance
Security.addProvider(bcProvider);
}
Pfx parsing
KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC");
ByteArrayInputStream baos = new ByteArrayInputStream(pfxFileContent);
keyStore.load(baos, password.toCharArray());
Enumeration aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
if (keyStore.isKeyEntry(alias )) {
Key key = keyStore.getKey(alias , keyPassword.toCharArray());
java.security.cert.Certificate certificate = keyStore.getCertificate(alias );
addKeyAndCertificateToStore((PrivateKey)key, (X509Certificate)certificate);
}
}
Aliases must be changed. The P12FromGostCSP utility always sets the same alias “csp_exported” and there will be problems processing the second key.
For convenience, the key from pfx must be loaded into the standard Java KeyStore and then work only with it.
Download KeyStore
FileInputStream is = new FileInputStream(keystorePath);
keystore = KeyStore.getInstance(KeyStore.getDefaultType());
char[] passwd = keystorePassword.toCharArray();
keystore.load(is, passwd);
Saving a key with a certificate in KeyStore
public void addKeyAndCertificateToStore(PrivateKey key, X509Certificate certificate) {
synchronized (this) {
keystore.setKeyEntry(alias.toLowerCase(), key, keyPassword.toCharArray(), new X509Certificate[] {certificate});
FileOutputStream out = new FileOutputStream(keystorePath);
keystore.store(out, keystorePassword.toCharArray());
out.close();
}
}
Download keys and certificates from KeyStore
Enumeration aliases = keystore.aliases();
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
if (keystore.isKeyEntry(alias)) {
Key key = keystore.getKey(alias, keyPassword.toCharArray());
keys.put(alias.toLowerCase(), key); //any key,value collection
Certificate certificate = keystore.getCertificate(alias);
if (certificate instanceof X509Certificate)
certificates.put(alias.toLowerCase(), (X509Certificate) certificate); //any key,value collection
}
}
File signature
CMSProcessableByteArray msg = new CMSProcessableByteArray(dataToSign);
List certList = new ArrayList();
certList.add(cert);
Store certs = new JcaCertStore(certList);
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
ContentSigner signer = new org.bouncycastle.operator.jcajce.JcaContentSignerBuilder("GOST3411WITHECGOST3410-2012-256").setProvider("BC").build(privateKey);
gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider("BC").build()).build(signer, certificate));
gen.addCertificates(certs);
CMSSignedData sigData = gen.generate(msg, false);
byte[] sign = sigData.getEncoded(); //result here
There is a JcaContentSignerBuilder option ("GOST3411WITHECGOST3410-2012-512") for 512 bit keys. My CAs issue 256 bit ones without asking anything and ignore clarifying questions.
Signature Verification
byte[] data = ...; //signed file data
byte[] signature = ...;//signature
boolean checkResult = false;
CMSProcessable signedContent = new CMSProcessableByteArray(data);
CMSSignedData signedData;
try {
signedData = new CMSSignedData(signedContent, signature);
} catch (CMSException e) {
return SIGNATURE_STATUS.ERROR;
}
SignerInformation signer;
try {
Store certStoreInSing = signedData.getCertificates();
signer = signedData.getSignerInfos().getSigners().iterator().next();
Collection certCollection = certStoreInSing.getMatches(signer.getSID());
Iterator certIt = certCollection.iterator();
X509CertificateHolder certHolder = (X509CertificateHolder) certIt.next();
X509Certificate certificate = new JcaX509CertificateConverter().getCertificate(certHolder);
checkResult = signer.verify(new JcaSimpleSignerInfoVerifierBuilder().build(certificate));
} catch (Exception ex) {
return SIGNATURE_STATUS.ERROR;
}
Signature verification is completely similar to the 2001 GOST verification. You can not change anything.
Summary
As a result of all the above actions, we got a relatively easy way to get rid of the heavy load of Crypto Pro in 2019.