Статус: Сотрудник
Группы: Участники
Зарегистрирован: 06.12.2008(UTC) Сообщений: 4,005 ![Российская Федерация Российская Федерация](/forum2/Content/images/flags/RU.png) Откуда: Крипто-Про Сказал(а) «Спасибо»: 21 раз Поблагодарили: 715 раз в 675 постах
|
Здравствуйте. Согласно используемому примеру, попробуйте так (настройки из этого примера остаются практически прежними, некоторые методы изменились): Код:
public class PKCS7EnvEphTransport {
/**
* Подписываемые/шифруемые данные.
*/
private static final byte[] DATA = ...
/**
* Контейнер получателя.
*/
private final static ISignatureContainer RECIPIENT = new EnvContainer2012_256(); // из samples
/**
* Извлечение параметров сертификата. Параметры шифрования
* обычно null, поэтому будут получены параметры шифрования
* по умолчанию.
* У AlgIdSpec есть несколько конструкторов (с использованием
* OID и др.).
*
* @param cert Сертификат.
* @return параметры сертификата.
* @throws Exception
*/
private static AlgIdSpec getAlgIdSpec(X509Certificate cert)
throws Exception {
byte[] encoded = cert.getPublicKey().getEncoded();
Asn1BerDecodeBuffer buf = new Asn1BerDecodeBuffer(encoded);
SubjectPublicKeyInfo keyInfo = new SubjectPublicKeyInfo();
try {
keyInfo.decode(buf);
} catch (Asn1Exception e) {
IOException ex = new IOException("Not GOST DH public key");
ex.initCause(e);
throw ex;
}
buf.reset();
return new AlgIdSpec(keyInfo.algorithm);
}
/**
* Зашифрование сообщения (enveloped).
*
* @param recipientCert - сертификат получателя.
* @param data - исходное сообщение (PKCS7).
* @return зашифрованное сообщение (enveloped).
* @throws Exception
*/
public static byte[] EncryptPKCS7(X509Certificate recipientCert,
byte[] data) throws Exception {
final PublicKey recipientPublic = recipientCert.getPublicKey();
// Генерирование симметричного ключа с параметрами
// шифрования из контрольной панели.
final KeyGenerator kg = KeyGenerator.getInstance(
CMStools.SEC_KEY_ALG_NAME, CRYPT_PROVIDER_NAME);
// Параметры шифрования симметричного ключа (по умолчанию)
// и параметры шифрования данных (по умолчанию).
final AlgIdSpec algIdSpec = getAlgIdSpec(recipientCert);
final ParamsInterface recipientTransportParameters = algIdSpec.getCryptParams(); // из открытого ключа
final ParamsInterface contentEncryptionParameters = algIdSpec.getCryptParams(); // могут быть другие
// Инициализация генератора.
kg.init(contentEncryptionParameters);
// Симметричный ключ.
final SecretKey symmetricKey = kg.generateKey();
// Зашифрование текста на симметричном ключе.
Cipher cipher = Cipher.getInstance(CIPHER_MODE, CRYPT_PROVIDER_NAME);
cipher.init(Cipher.ENCRYPT_MODE, symmetricKey, (SecureRandom) null);
final byte[] iv = cipher.getIV();
final byte[] text = cipher.doFinal(data, 0, data.length);
// Зашифрование симметричного ключа.
final byte[] keyTransport = wrap(symmetricKey, recipientPublic,
recipientTransportParameters);
// Формирование CMS-сообщения.
final ContentInfo all = new ContentInfo();
all.contentType = new Asn1ObjectIdentifier(new OID(CMStools.STR_CMS_OID_ENVELOPED).value);
final EnvelopedData cms = new EnvelopedData();
all.content = cms;
cms.version = new CMSVersion(0);
cms.recipientInfos = new RecipientInfos(1);
cms.recipientInfos.elements = new RecipientInfo[1];
cms.recipientInfos.elements[0] = new RecipientInfo();
final KeyTransRecipientInfo key_trans = new KeyTransRecipientInfo();
key_trans.version = new CMSVersion(0);
final Asn1BerEncodeBuffer ebuf = new Asn1BerEncodeBuffer();
final AlgorithmIdentifier id = (AlgorithmIdentifier) algIdSpec.getDecoded();
id.encode(ebuf);
Asn1BerDecodeBuffer dbuf = new Asn1BerDecodeBuffer(ebuf.getMsgCopy());
key_trans.keyEncryptionAlgorithm = new KeyEncryptionAlgorithmIdentifier();
key_trans.keyEncryptionAlgorithm.decode(dbuf);
ebuf.reset();
dbuf.reset();
key_trans.rid = new RecipientIdentifier();
final IssuerAndSerialNumber issuer = new IssuerAndSerialNumber();
final X500Principal issuerName = recipientCert.getIssuerX500Principal();
dbuf = new Asn1BerDecodeBuffer(issuerName.getEncoded());
issuer.issuer = new Name();
final RDNSequence rnd = new RDNSequence();
rnd.decode(dbuf);
issuer.issuer.set_rdnSequence(rnd);
issuer.serialNumber = new CertificateSerialNumber(recipientCert.getSerialNumber());
key_trans.rid.set_issuerAndSerialNumber(issuer);
dbuf.reset();
key_trans.encryptedKey = new EncryptedKey(keyTransport);
ebuf.reset();
cms.recipientInfos.elements[0].set_ktri(key_trans);
cms.encryptedContentInfo = new EncryptedContentInfo();
final OID contentType = new OID(CMStools.STR_CMS_OID_DATA);
cms.encryptedContentInfo.contentType = new ContentType(contentType.value);
final Gost28147_89_Parameters parameters = new Gost28147_89_Parameters();
parameters.iv = new Gost28147_89_IV(iv);
parameters.encryptionParamSet = new Gost28147_89_ParamSet(contentEncryptionParameters.getOID().value); // параметры шифрования данных
cms.encryptedContentInfo.contentEncryptionAlgorithm = new ContentEncryptionAlgorithmIdentifier(
_Gost28147_89_EncryptionSyntaxValues.id_Gost28147_89, parameters);
cms.encryptedContentInfo.encryptedContent = new EncryptedContent(text);
all.encode(ebuf);
return ebuf.getMsgCopy();
}
/**
* Расшифрование PKCS7 (Enveloped).
*
* @param recipientAlias - алиас получателя.
* @param recipientPassword - пароль получателя.
* @param enveloped - зашифрованное сообщение (Enveloped).
* @param data - исходные данные (нужны при проверке detached CMS подписи).
* @param detached - флаг detached подписи.
* @return результат проверки.
* @throws Exception
*/
public static boolean DecryptPKCS7(String recipientAlias, char[]
recipientPassword, byte[] enveloped, byte[] data, boolean
detached) throws Exception {
// Разбор CMS-сообщения.
Asn1BerDecodeBuffer dbuf = new Asn1BerDecodeBuffer(enveloped);
final ContentInfo all = new ContentInfo();
all.decode(dbuf);
dbuf.reset();
final EnvelopedData cms = (EnvelopedData) all.content;
KeyTransRecipientInfo key_trans;
// Только key_trans.
if (cms.recipientInfos.elements[0].getChoiceID() == RecipientInfo._KTRI) {
key_trans = (KeyTransRecipientInfo) (cms.recipientInfos.elements[0].getElement());
}
else {
throw new Exception("Unknown recipient info");
}
final byte[] wrapKey = key_trans.encryptedKey.value;
final Gost28147_89_Parameters params = (Gost28147_89_Parameters)
cms.encryptedContentInfo.contentEncryptionAlgorithm.parameters;
final byte[] iv = params.iv.value;
final OID cipherOID = new OID(params.encryptionParamSet.value); // параметры шифрования данных
final byte[] text = cms.encryptedContentInfo.encryptedContent.value;
// Получатель - закрытый ключ.
final JCPProtectionParameter protectionParameter =
new JCPProtectionParameter(recipientPassword);
final JCPPrivateKeyEntry recipientEntry = (JCPPrivateKeyEntry) keyStore
.getEntry(recipientAlias, protectionParameter);
// Выработка ключа согласования получателем и
// расшифрование симметричного ключа.
final SecretKey symmetricKey = unwrap(wrapKey,
recipientEntry.getPrivateKey());
// Расшифрование текста на симметричном ключе.
final GostCipherSpec spec = new GostCipherSpec(iv, cipherOID);
Cipher cipher = Cipher.getInstance(CIPHER_MODE, CRYPT_PROVIDER_NAME);
cipher.init(Cipher.DECRYPT_MODE, symmetricKey, spec, null);
final byte[] result = cipher.doFinal(text, 0, text.length);
Array.writeFile(TEST_DIR + "cms_cms.bin", result);
// checkPKCS7(result, detached, data, TEST_DIR + "cms_cms_data.txt");
return true;
}
/**
* Зашифрование сессионного ключа.
*
* @param secretKey Сессионный ключ.
* @param recipientKey Открытый ключ получателя.
* @return транспортная структура GostR3410_KeyTransport.
* @throws Exception
*/
private static byte[] wrap(SecretKey secretKey, PublicKey
recipientKey, ParamsInterface recipientTransportParameters)
throws Exception {
// Определение алгоритма эфемерного ключа.
String keyAlgorithm = recipientKey.getAlgorithm();
String ephKeyAlgorithm = JCP.GOST_EL_DH_EPH_NAME;
if (keyAlgorithm.equalsIgnoreCase(JCP.GOST_EL_2012_256_NAME)) {
ephKeyAlgorithm = JCP.GOST_EPH_DH_2012_256_NAME;
} // if
else if (keyAlgorithm.equalsIgnoreCase(JCP.GOST_EL_2012_512_NAME)) {
ephKeyAlgorithm = JCP.GOST_EPH_DH_2012_512_NAME;
} // else
// Генерация эфемерной пары.
KeyPairGenerator kgp = KeyPairGenerator.getInstance(
ephKeyAlgorithm, CRYPT_PROVIDER_NAME);
// Устанавливаем нужные параметры, как у
// получателя.
AlgorithmParameterSpec spec = new X509PublicKeySpec(recipientKey.getEncoded());
kgp.initialize(spec);
// Генерируем эфемерную пару. Ключи получат
// параметры recipientKey, а у него параметры
// - recipientTransportParameters.
KeyPair ephPair = kgp.generateKeyPair();
PrivateKey privateKey = ephPair.getPrivate();
PublicKey publicKey = ephPair.getPublic();
byte[] syncro = new byte[8];
SecureRandom random = SecureRandom.getInstance(JCP.CP_RANDOM, PROVIDER_NAME);
random.nextBytes(syncro);
IvParameterSpec iv = new IvParameterSpec(syncro);
// Выработка ключа согласования.
KeyAgreement ka = KeyAgreement.getInstance(privateKey.getAlgorithm(), CRYPT_PROVIDER_NAME);
ka.init(privateKey, iv);
ka.doPhase(recipientKey, true);
Key dh = ka.generateSecret(CIPHER); // dh получит параметры из privateKey, т.е. recipientTransportParameters
// Зашифрование симметричного ключа на ключе согласования
// отправителя. Передаются параметры шифрования ключа, если
// отличаются от тех, что у dh.
final Cipher cipher = Cipher.getInstance(CIPHER, CRYPT_PROVIDER_NAME);
cipher.init(Cipher.WRAP_MODE, dh, recipientTransportParameters, (SecureRandom) null);
final byte[] wrappedKey = cipher.wrap(secretKey);
// Упаковка параметров и ключа.
Gost28147_89_EncryptedKey encryptedKey = new Gost28147_89_EncryptedKey();
Asn1BerDecodeBuffer decoder = new Asn1BerDecodeBuffer(wrappedKey);
encryptedKey.decode(decoder);
byte[] imita = encryptedKey.macKey.value;
byte[] wrapperKeyBytes = encryptedKey.encryptedKey.value;
// Кодирование открытого ключа в SubjectPublicKeyInfo.
byte[] publicKeyBytes = publicKey.getEncoded();
SubjectPublicKeyInfo publicKeyInfo = new SubjectPublicKeyInfo();
decoder = new Asn1BerDecodeBuffer(publicKeyBytes);
publicKeyInfo.decode(decoder);
// Кодирование GostR3410_KeyTransport.
GostR3410_KeyTransport keyTransport = new GostR3410_KeyTransport();
Asn1BerEncodeBuffer encoder = new Asn1BerEncodeBuffer();
keyTransport.sessionEncryptedKey = new Gost28147_89_EncryptedKey(wrapperKeyBytes, imita);
keyTransport.transportParameters = new GostR3410_TransportParameters(
new Gost28147_89_ParamSet(recipientTransportParameters.getOID().value), // параметры шифрования ключа
publicKeyInfo,
new Asn1OctetString(iv.getIV()));
keyTransport.encode(encoder);
return encoder.getMsgCopy();
}
/**
* Зашифрование сессионного ключа.
*
* @param wrappedKey Зашифрованный сессионный ключ (транспортная
* структура GostR3410_KeyTransport).
* @param recipientKey Закрытый ключ получателя.
* @return сессионный ключ.
* @throws Exception
*/
private static SecretKey unwrap(byte[] wrappedKey, Key
recipientKey) throws Exception {
// Декодирование GostR3410_KeyTransport.
GostR3410_KeyTransport keyTransport = new GostR3410_KeyTransport();
Asn1BerDecodeBuffer decoder = new Asn1BerDecodeBuffer(wrappedKey);
keyTransport.decode(decoder);
// EncryptedKey в правильном формате для шифратора.
byte[] wrappedKeyBytes = keyTransport.sessionEncryptedKey.encryptedKey.value;
byte[] imita = keyTransport.sessionEncryptedKey.macKey.value;
Asn1BerEncodeBuffer encoder = new Asn1BerEncodeBuffer();
Gost28147_89_EncryptedKey encryptedKey = new Gost28147_89_EncryptedKey(
new Gost28147_89_Key(wrappedKeyBytes), null, new Gost28147_89_MAC(imita));
encryptedKey.encode(encoder);
byte[] wrapped = encoder.getMsgCopy();
// Декодирование открытого ключа.
encoder.reset();
keyTransport.transportParameters.ephemeralPublicKey.encode(encoder);
byte[] encodedPublic = encoder.getMsgCopy();
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedPublic);
KeyFactory kf = KeyFactory.getInstance(recipientKey.getAlgorithm(), PROVIDER_NAME);
PublicKey publicKey = kf.generatePublic(keySpec);
// Параметры шифрования.
IvParameterSpec iv = new IvParameterSpec(keyTransport.transportParameters.ukm.value);
OID transportParametersOid = new OID(keyTransport.transportParameters.encryptionParamSet.value); // параметры шифрования ключа
CryptParamsSpec uz = CryptParamsSpec.getInstance(transportParametersOid);
GostCipherSpec params = new GostCipherSpec(iv, uz);
// Выработка ключа согласования.
KeyAgreement ka = KeyAgreement.getInstance(recipientKey.getAlgorithm(), CRYPT_PROVIDER_NAME);
ka.init(recipientKey, iv);
ka.doPhase(publicKey, true);
Key dh = ka.generateSecret(CIPHER); // dh получит параметры из recipientKey, т.е., по идее, transportParametersOid
// Расшифрование сессионного ключа.
Cipher cipher = Cipher.getInstance(CIPHER, CRYPT_PROVIDER_NAME);
cipher.init(Cipher.UNWRAP_MODE, dh, params);
return (SecretKey) cipher.unwrap(wrapped, null, Cipher.SECRET_KEY);
}
...
public static void main(String[] args) throws Exception {
byte[] enveloped = EncryptPKCS7(RECIPIENT.getAlias(), DATA);
DecryptPKCS7(RECIPIENT.getAlias(), RECIPIENT.getPassword(), enveloped, null, false);
// "C:\Program Files\Crypto Pro\CSP\csptest" -lowenc -decrypt -in "jcp_enveloped_cms.bin" -out "decrypted.txt" -my <installed_recipient_RECIPIENT>
}
Вообще, часть wrap/unwrap можно заменить с помощью алгоритма Cipher - "GostTransport": он также генерирует эфемерный ключ, экспортирует/импортирует его и т.д. Отредактировано пользователем 9 ноября 2018 г. 9:43:59(UTC)
| Причина: Не указана |