Jump to content

Recommended Posts

Добрый день, коллеги!

Не получается реализовать обмен шифрованными xml-сообщениями с ФСС - их сервис сообщает, что не может расшифровать сообщения

Сейчас смотрю - мне не нравится длина отправляемого им в сообщении ключа. Всего 44 байта (в Base64 encoding - 60 байт). В инете нашёл пример ответа их сервиса - там длина ключа в Base64 encoding ~ 220 байт

Вопрос (смущаясь) - 44 байта - это не слишком коротко?

Ниже изложу каким образом у меня это получается

Благодарю за внимание,

Николай

Share this post


Link to post
Share on other sites

Код

    public    javax.xml.soap.SOAPMessage    putMessageInEncryptEnvelope(lotus.domino.Session session, javax.xml.soap.SOAPMessage message)    {
        try    {
            X509Certificate certificate = (X509Certificate) this.keyEntry.getCertificate();

            java.security.PublicKey publicKey = certificate.getPublicKey();
            System.out.println("Длина иоего открытого ключа: ".concat(Integer.toString(certificate.getPublicKey().getEncoded().length)));
            
            java.security.PublicKey respondentKey = this.getRespondentKey(session);
            System.out.println("Длина открытого ключа респондента: ".concat(Integer.toString(respondentKey.getEncoded().length)));

            // получение алгоритма согласования ключей ГОСТ Р 34.10-2001
            javax.crypto.KeyAgreement agreement = javax.crypto.KeyAgreement.getInstance(
                    "GOST3410-2001DH", // название алгоритма
                    "ViPNet" // название провайдера
            );            // создание нового случайного секретного ключа
            // подготовка вектора инициализации (8 байт)
            java.security.SecureRandom random = new java.security.SecureRandom();
            byte[] inputIV = new byte[8];
            random.nextBytes(inputIV);
             // инициализация процесса согласования
                agreement.init(
                    this.privateKey, // собственный закрытый ключ
                    new javax.crypto.spec.IvParameterSpec(inputIV) // вектор инициализации
                );
            // выполнение следующей фазы процесса
            agreement.doPhase(
                respondentKey, // открытый ключ второго участника
                true // признак последней фазы
            );
            javax.crypto.SecretKey secretKey = agreement.generateSecret(
                    "GOST28147-89" // алгоритм секретного ключа
            );

            javax.crypto.SecretKey encryptKey = this.generateSecretKeyWithGOST28147_89(ru.infotecs.crypto.random.ViPNetRandom.getViPNetRandom());
            //    Экспорт ключей по алгоритму ГОСТ 28147-89
            // подготовка параметров зашифрования
            // подготовка набора параметров работы алгоритма ГОСТ 28147-89
            random = new java.security.SecureRandom();
            byte[] iv = new byte[8];
            random.nextBytes(iv);

            ru.infotecs.crypto.gost28147.Gost28147ParamSet paramSet = ru.infotecs.crypto.gost28147.Gost28147ParamSet.CryptoPro_A;
            // создание параметров зашифрования
            java.security.spec.AlgorithmParameterSpec params = new ru.infotecs.crypto.gost28147.Gost28147CipherParameterSpec(
                    paramSet,
                    iv
            );
            //создание шифратора
            javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("GOST28147-89/ECB/NoPadding", "ViPNet");
            cipher.init(javax.crypto.Cipher.WRAP_MODE, secretKey, params);
            final byte[] wrap = cipher.wrap(encryptKey);
            System.out.println("Алгоритм секретного ключа: ".concat(encryptKey.getAlgorithm()));
            System.out.println("Длина экспортированного ключа: ".concat(Integer.toString(wrap.length)));
            String    key = javax.xml.bind.DatatypeConverter.printBase64Binary(wrap);
        }
        catch (Exception    e)    {e.printStackTrace();}
        return null;
    }

Функция генерации секретного ключа

   private static javax.crypto.SecretKey generateSecretKeyWithGOST28147_89(ru.infotecs.crypto.random.ViPNetRandom inputRandom) throws Exception {
        // получение генератора секретных ключей ГОСТ 28147-89
        javax.crypto.KeyGenerator generator = javax.crypto.KeyGenerator.getInstance(
                "GOST28147-89", // название алгоритма
                "ViPNet"        // название провайдера
        );

        // подготовка параметров работы генератора
        // подготовка источника случайных чисел
        ru.infotecs.crypto.random.ViPNetRandom random = inputRandom;
        // создание параметров работы генератора
        java.security.spec.AlgorithmParameterSpec params = new ru.infotecs.crypto.gost28147.Gost28147KeyGeneratorParameterSpec(
                random
        );

        // рекомендуемый способ принудительной инициализации генератора
        generator.init(params);

        // допустимые способы принудительной инициализации генератора
        generator.init(params, new java.security.SecureRandom()); // параметр SecureRandom игнорируется
        generator.init(new java.security.SecureRandom()); // параметр SecureRandom игнорируется
        generator.init(256);
        generator.init(256, new java.security.SecureRandom()); // параметр SecureRandom игнорируется

        // создание нового случайного секретного ключа
        javax.crypto.SecretKey secretKey = generator.generateKey();

        return secretKey;
    }

Консоль

printing: Длинамоего открытого ключа: 101
printing: Длина открытого ключа респондента: 101
printing: Алгоритм секретного ключа: GOST28147-89
printing: Длина экспортированного ключа: 44

Share this post


Link to post
Share on other sites

вот здесь https://tools.ietf.org/html/rfc4357#section-6.1 нашёл, что вроде в самый раз, а остальное - наоборот, отклонение от нормы

6.2. GOST 28147-89 Key Unwrap

This algorithm decrypts GOST 28147-89 CEK with a GOST 28147-89 KEK.

The GOST 28147-89 key unwrap algorithm is:

1) If the wrapped content-encryption key is not 44 octets, then error.

2) Decompose the wrapped content-encryption key into UKM, CEK_ENC, and CEK_MAC. UKM is the most significant (first) 8 octets. CEK_ENC is next 32 octets, and CEK_MAC is the least significant (last) 4 octets. 3) Decrypt CEK_ENC in ECB mode using the KEK. Call the output CEK. 4) Compute a 4-byte checksum value, gost28147IMIT (UKM, KEK, CEK), compare the result with CEK_MAC. If they are not equal, then error.

тогда что же здесь такое? https://www.cryptopro.ru/forum2/default.aspx?g=posts&t=12490

<xenc:CipherData><xenc:CipherValue>MIGkMCgEIO2FGPUYGOzVpHm6ZY+TnjG+vjY6KHT2uRAgIpKRGvGMBASz+OPeoHgGByqFAwICHwGg
YzAcBgYqhQMCAhMwEgYHKoUDAgIkAAYHKoUDAgIeAQNDAARASufCGsZYH3IEQw8+H1SF+HyKKZBy
YDgWdLMj1rmNyMhb4lQNdahkLxkGO+gyTl2EaSeJj2+xMdU0sUugtuhLygQITJY4xUhcMWY=</xenc:CipherValue></xenc:CipherData>

Какой ключ шлётся в качестве сессионного? и какой , может быть, ждут от меня?

Благодарю. Николай

Share this post


Link to post
Share on other sites

<quote>The CipherValue for such encrypted key is the base64 encoding of the [X.208-88] DER encoding of a GostR3410-KeyTransport structure (see section 4.2.1 of [CPCMS])</quote>

вот отсюда:

https://tools.ietf.org/html/draft-chudov-cryptopro-cpxmldsig-08#section-6.9

правильно ли я понял, что wrapped ключ мне необходимо сперва закодировать DER encoding, а потом base64 encoding?

Share this post


Link to post
Share on other sites

Закрою тему. Проблема, по всей видимости, в недостаточной стандартности сервиса - пришлось для шифрования/дешифрования использовать аналогичную сервису dll на основе вот этого проекта

https://github.com/AlexMAS/GostCryptography

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×

Important Information

By using this site, you agree to our Terms of Use.