Сервис Реестры платежей позволяет отправлять до пяти тысяч платёжных поручений в одном реестре. Это упрощает учёт платежей в адрес разных получателей: на свои счета, счета контрагентов - физических лиц и организаций.
Механизм отправки реестра платежей
Формирование и передача подписи реестра платежей
Для подписания реестра рублёвых платежей на шаге 3 необходимо сформировать подпись и передать её в методе «Создание запроса на подписание реестра платежей» в параметре digestSignatures .
Подписывать необходимо набор значимых полей платёжного документа, который возвращается в параметре content в ответе от метода «Изменение статуса реестра платежей» на шаге 2 инструкции, при переводе реестра в статус «На подпись».
Для передачи подписи используется массив digestSignatures тела запроса со следующей структурой объектов массива:
Электронные подписи по дайджесту документа
Значение ЭП документа, закодированное в Base64
Серийный номер RSA-сертификата. Заполняется значением поля serialNumber из ответа метода «Получение RSA-сертификата», если signatureType = RSA
Тип электронной подписи (RSA или УКЭП)
1"digestSignatures": [
2 {
3 "base64Encoded": "HlaeIHXXEcGT1bFxo1NlpAzpr+kJ2IQrcxVdvDTep6xjsmD1FDb+6NIyLT+/T24S0mPfVCU75sieOMt71TBS7w==",
4 "certificateUuid": "61000366d11e143acbc03a56d70001000366d1",
5 "signatureType": "RSA"
6 }
7]
Подписание по алгоритму RSA
Для подписания необходимо использовать сертификат, выпущенный в Альфа-Бизнес, или сертификат, выпущенный в Alfa API при помощи сервиса Электронная подпись.
Требования к передаваемой электронной подписи:
-
•формат подписи - PKCS#7 Attached;
-
•алгоритм электронной подписи - sha256WithRSAEncryption.
При подписании по алгоритму RSA можно передать одну или несколько электронных подписей.
1 public static String KEYSTORE_PATH = "";
2 public static String SIGNATURE_ALGORYTHM = "";
3 public static String KEYSTORE_PASSWORD = "";
4 public static String KEYSTORE_TYPE = "";
5 public static String KEYSTORE_ALIAS = "";
6
7 public static String signDataWithRSA(String dataToSign, String p12FileName)
8 throws KeyStoreException, OperatorCreationException, CertificateEncodingException, IOException, CMSException {
9
10 Security.addProvider(new BouncyCastleProvider());
11 BouncyCastleProvider provider = (BouncyCastleProvider) Security.getProvider("BC");
12
13 KeyStore keyStore = loadKeyStore(String.format(KEYSTORE_PATH, p12FileName));
14 X509Certificate certificate = getCertificate(keyStore);
15 X509CertificateHolder certificateHolder = new X509CertificateHolder(certificate.getEncoded());
16
17 CMSSignedDataGenerator signedDataGen = new CMSSignedDataGenerator();
18 ContentSigner signer = new JcaContentSignerBuilder(SIGNATURE_ALGORYTHM).setProvider(provider)
19 .build(getKey(keyStore));
20 signedDataGen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(
21 new JcaDigestCalculatorProviderBuilder().setProvider(provider).build())
22 .build(signer, certificateHolder));
23 signedDataGen.addCertificates(new JcaCertStore(List.of(certificate)));
24
25 CMSSignedData signedData = signedDataGen.generate(new CMSProcessableByteArray(dataToSign.getBytes()), false);
26 return new String(Base64.getEncoder().encode(signedData.getEncoded("DER")));
27 }
28
29 private static KeyStore loadKeyStore(String keystoreFilePath) throws KeyStoreException {
30 KeyStore keystore = KeyStore.getInstance(KEYSTORE_TYPE);
31 try (InputStream inputStream = new FileInputStream(keystoreFilePath)) {
32 keystore.load(inputStream, KEYSTORE_PASSWORD.toCharArray());
33 } catch (IOException | NoSuchAlgorithmException | CertificateException e) {
34 throw new RuntimeException("Ошибка открытия хранилища ключей", e);
35 }
36 return keystore;
37 }
38
39 private static X509Certificate getCertificate(KeyStore keyStore) {
40 try {
41 return (X509Certificate) keyStore.getCertificate(KEYSTORE_ALIAS);
42 } catch (KeyStoreException e) {
43 throw new RuntimeException("Ошибка получения сертификата", e);
44 }
45 }
46
47 private static PrivateKey getKey(KeyStore keyStore) {
48 try {
49 return (PrivateKey) (keyStore.getKey(KEYSTORE_ALIAS, KEYSTORE_PASSWORD.toCharArray()));
50 } catch (KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException e) {
51 throw new RuntimeException("Ошибка получения закрытого ключа", e);
52 }
53 }
В качестве альтернативы можно использовать готовую реализацию - SDK для подписи. Для подписания платёжных поручений при создании экземпляра класса CmsSignatureService необходимо задать кодировку передачи подписи, установив значение константы SignedDataEncoding.DER .
Для подписания данных с использованием подкреплённой подписи воспользуйтесь методом signAttached(byte[] data) .
1CmsSignatureService cmsSignatureService = new CmsSignatureServiceImpl(
2KeyStoreParameters.builder()
3 .path("/path/to/keystore")
4 .type(KeyStoreParameters.KeyStoreType.JKS)
5 .password("example")
6 .privateKey(PrivateKeyParameters.builder()
7 .alias("example")
8 .password("example")
9 .build())
10 .certificate(CertificateParameters.builder()
11 .alias("example")
12 .build())
13 .build(),
14 SignatureAlgorithm.RSA,
15 SignedDataEncoding.DER
16);
Подписание по алгоритму ГОСТ
Для подписания может использоваться сертификат УКЭП, выпущенный любым аккредитованным УЦ. Если сертификат принадлежит лицу, обладающим правом подписи по уставу компании, то он самодостаточен. Если сертификат выпущен для уполномоченного лица, обладающего правом подписи по доверенности, то, помимо сертификата, потребуется выпустить машиночитаемую доверенность (МЧД) и зарегистрировать её в Альфа-Банке, используя метод «Запрос на регистрацию МЧД в банке» по инструкции.
Запрос на подписание реестра платежей должен быть отправлен от лица пользователя, на чье имя выпущен сертификат УКЭП, использованный для подписания реестра, и зарегистрирована МЧД (если вы используете МЧД).
При подписании УКЭП в массиве digestSignatures можно передать только одну подпись.