الهروب من تشفير برو. GOST 34.10-2012 الطبعة

يوجد على Habré مقال رائع بعنوان " Escape from Crypto Pro. إصدار المخرج ، SMEV-edition " ، لكن عام 2019 جاء وبدأت جميع CAs في إصدار التواقيع الرقمية وفقًا لـ GOST 34.10-2012 بدلاً من GOST 34.10-2001.

تحت القص ، قصة حول كيف يمكنك تعديل برنامجك على Bouncy Castle لدعم العمل مع مفاتيح للضيوف الجدد.

الصورة

إخلاء المسؤولية


لا أعرف أي شيء عن التعقيدات القانونية لتوقيع المستندات من خلال Bouncy Castle وأنظمة حماية معلومات التشفير الأخرى ولست مستعدًا للتواصل. قبل استخدام الكود في الإنتاج ، استشر محامًا.

لماذا هذا ضروري حتى؟ المادة الأصلية مكتوبة بشكل جيد. لن أكرر نفسي.

الحصول على مفتاح من الرمز


الصورة

جميع المراجع المصدقة المعروفة لي تصدر مفاتيح بشهادات على رموز مشابهة. الحاوية cryptoPro مع المفتاح الخاص والشهادة مكتوبة على الرمز المميز. عند تصدير مفتاح من خلال CryptoPro CSP ، يتم تصديره إلى "CryptoPro pfx" خاص لا يتوافق مع أي شيء.

يتم تجاهل طلبات إصدار مفتاح في pfx قياسي أو أي حاوية CA نموذجية أخرى.
إذا كان أي شخص يعرف إصدار المرجع المصدق (CA) في حاويات قياسية ، شارك الإحداثيات في التعليقات. الناس الطيبين لا يخجلون من الترويج.

لتحويل حاوية CryptoPro إلى pfx قياسي ، سنستخدم P12FromGostCSP ، كما في المقالة الأصلية. لا تعمل الإصدارات القديمة المخترقة مع مفاتيح لعام 2012 Gost. نذهب إلى موقع المؤلفين وشراء واحدة جديدة.

لذلك حصلنا على pfx القياسية مع المفتاح والشهادة.

نطاط القلعة التحديث

نقوم بتحديث Bouncy Castle إلى 1.60 قد لا تدعم الإصدارات الأقدم خوارزميات GOST 2012.

<dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.60</version> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk15on</artifactId> <version>1.60</version> </dependency> 

تهيئة نطاط القلعة

  static { BouncyCastleProvider bcProvider = new BouncyCastleProvider(); String name = bcProvider.getName(); Security.removeProvider(name); // remove old instance Security.addProvider(bcProvider); } 

Pfx تحليل

 KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC"); ByteArrayInputStream baos = new ByteArrayInputStream(pfxFileContent); keyStore.load(baos, password.toCharArray()); Enumeration<String> 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); } } 

يجب تغيير الأسماء المستعارة. تقوم الأداة المساعدة P12FromGostCSP دائمًا بتعيين الاسم المستعار نفسه "csp_exported" وستكون هناك مشكلات في معالجة المفتاح الثاني.

للراحة ، يجب تحميل المفتاح من pfx في Java KeyStore القياسي ومن ثم العمل معه فقط.

تحميل KeyStore

 FileInputStream is = new FileInputStream(keystorePath); keystore = KeyStore.getInstance(KeyStore.getDefaultType()); char[] passwd = keystorePassword.toCharArray(); keystore.load(is, passwd); 

حفظ مفتاح مع شهادة في 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(); } } 

قم بتنزيل المفاتيح والشهادات من KeyStore

 Enumeration<String> 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 } } 

توقيع الملف

 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 

يوجد خيار JcaContentSignerBuilder ("GOST3411WITHECGOST3410-2012-512") لمفاتيح 512 بت. تصدر شهادات الاعتماد الخاصة بي 256 بت دون طرح أي شيء وتجاهل الأسئلة التوضيحية.

التحقق من التوقيع

 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<X509CertificateHolder> 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; } 

يشبه التحقق من التوقيع تمامًا التحقق من GOST لعام 2001. لا يمكنك تغيير أي شيء.

ملخص


نتيجة لجميع الإجراءات المذكورة أعلاه ، حصلنا على طريقة سهلة نسبيًا للتخلص من الحمل الثقيل لـ Crypto Pro في عام 2019.

Source: https://habr.com/ru/post/ar440882/


All Articles