| ||||
| ||||
Подпись сделанная в CSP не проверяется в JCP и наоборот. Эти два продукта совместимы между собой? | ||||
Ответы: | ||||
| ||||
Нашел вопрос, который задавали в этом форуме - http://cryptopro.ru/cryptopro/forum/view.asp?q=2355 У меня абсолютно такая же ситуация. Только на тот вопрос так и не ответили. Может разработчики CSP все-таки ответят на вопрос, что именно подписывает функция CryptSignMessage? На сколько я понимаю, JCP генерирует такую же подпись как и функция CryptSignMessage, только вот по ГОСТу ли это? | ||||
| ||||
Все по ГОСТ работает. Попробуйте объект подписи запрашивать так: Signature sig = Signature.getInstance("CryptoProSignature"); | ||||
| ||||
Все равно не проверяется. Вот код который генерирует подпись при помощи CAPILite под Солярисом: if( CryptAcquireContext(&hProv, (const char *)pContainer, NULL, typeProv, 0) ) { /* * Создаем хеш. */ if ( CryptCreateHash(hProv, CALG_GR3411, 0, 0, &hHash) ) { /* * Устанавливаем HP_OID. * Заносим данные в созданный хеш и подписываем их. */ if ( CryptSetHashParam(hHash,HP_OID,(BYTE*)OID_HashVerbaO, 0) && CryptSetHashParam(hHash, HP_HASHVAL, (const BYTE *)pHash, 0) ) { if( CryptSignHash( hHash, AT_SIGNATURE, NULL, 0, NULL, &cbSignature) ) { isKey = TRUE; setKey = AT_SIGNATURE; } else if( CryptSignHash( hHash, AT_KEYEXCHANGE, NULL, 0, NULL, &cbSignature) ) { printf("sign: SIGNATURE key not found. Using KEYEXCHANGE key.\n"); isKey = TRUE; setKey = AT_KEYEXCHANGE; } if( isKey && (pbSignature = new BYTE[cbSignature]) ) { if( CryptSignHash(hHash, setKey, NULL, 0, pbSignature, &cbSignature) ) { /* * Возвращаем подписанные данные. */ .... } else { PrintError("4. Error CryptSignHash"); } delete[] pbSignature; } else { PrintError("4. Error CryptSignHash or size"); } } else { PrintError("4. Error CryptSetHashParam or size"); } CryptDestroyHash(hHash); } else { PrintError("4. Error CryptCreateHash"); } CryptReleaseContext(hProv, 0); } else { PrintError("4. Error CryptAcquireContext"); } Код проверки на Java при помощи JCP под Линуксом: public abstract class AbstractTest { // данные, которые будут подписываться public static final String DATA_FOR_SIGN = "Data for sign."; // Digest: И CSP и JCP генерируют одинаковый дайджест // -17 39 -37 66 -51 -43 -76 37 8 -113 -122 52 40 -58 -75 -18 55 -62 -60 82 61 41 -88 82 -126 106 -48 -94 63 18 43 110 // цифровая подпись вычисленная с данных - AbstractTest#DATA_FOR_SIGN. public static final byte[] SIGNATURE = { -10, -46, -40, 68, -43, 67, -58, -54, -92, 27, -85, -45, 89, 107, -52, -35, -66, -127, 3, -104, -78, -59, -90, 102, -14, -12, -100, -122, -48, -47, -12, 46, -59, 34, -31, 68, -6, -67, -84, -110, 64, -101, -23, 72, 35, 51, -23, -22, 116, -76, -20, -29, -26, -13, -15, 104, 77, 109, -96, -107, -15, -86, -25, -70, }; // Подпись сгенерированная CSP. Самим CSP проверяется, как под Линуксом, так и под Солярисом. // название алгоритма хеширования public static final String MESSAGE_DIGEST_ALGORITHM = «GOST3411»; // название алгоритма ЭЦП. public static final String SIGNATURE_ALGORITHM = «GOST3411withGOST3410EL»; // public static final String SIGNATURE_ALGORITHM = «CryptoProSignature»; // так тоже не проверяется ... } public class VerifyTest extends AbstractTest { public VerifyTest() { } public static void main( String[] args ) { try { System.out.println( "Validation begin..." ); System.out.println( "Store type - " + STORE_TYPE ); System.out.println( "Container name - " + USER_ALIAS ); // загружаем хранилище сертификатов и закрытых ключей KeyStore store = KeyStore.getInstance( STORE_TYPE ); store.load( null, null ); // получаем сертификат из хранилища X509Certificate cert = ( X509Certificate )store.getCertificate( USER_ALIAS ); // Получаем открытый ключ из сертификата PublicKey pubKey = cert.getPublicKey(); // вычисляем дайджест из данных, чья ЭЦП будет проверяться MessageDigest digest = MessageDigest.getInstance( MESSAGE_DIGEST_ALGORITHM ); digest.update( DATA_FOR_SIGN.getBytes() ); byte[] digestedData = digest.digest(); outByteArray( digestedData, "Digest:" ); // проверяем подпись Signature sig = Signature.getInstance( SIGNATURE_ALGORITHM ); sig.initVerify( pubKey ); sig.update( digestedData ); boolean success = sig.verify( SIGNATURE ); if ( success ) { System.out.println( "Validation SUCCESSFUL." ); } else { System.out.println( "Validation FAILED." ); } //verify(); } catch ( Exception e ) { e.printStackTrace(); } } } Код возвращает - Validation FAILED. В чем может быть проблема ? CSP используется версии 3.0. | ||||
| ||||
Ради эксперимента сделал следующее: Сделал подпись в JCP со следующим параметром – Signature.getInstance("CryptoProSignature"), проверил с таким же параметром, подпись проверяется. Затем сгенерированную ранее подпись проверил с параметром Signature.getInstance("GOST3411withGOST3410EL"), JCP сказал, что подпись не валидна. Объясните пожалуйста, если указан параметр «CryptoProSignature», по какому алгоритму генерируется/проверяется подпись? В документации к JCP описание параметра CryptoProSignature я не нашел. Какое-то раздвоение ГОСТ-ов получается. | ||||
| ||||
Разница между этими алгоритмами в порядке байтов в массиве подписи :) Других отличий нет. "Алгоритм" "CryptoProSignature" был введен специально для совместимости с подписью CSP. Сейчас я попробую запустить ваш пример. | ||||
| ||||
Странная ситуация возникла. При формировании подписи в CSP я сначала высчитывал дайджест с подписываемых данных (CryptCreateHash()) и подписывал потом именно его (CryptSignHash()). При проверке этой подписи на Java я высчитывал дайджест с тех же самых данных (Digest#digest()) и полученное значение передавал в метод Signature#update(). В метод Signature#verify() передавал подпись сгенерированную CSP. Подпись не проверялась. Но если в Java при проверке подписи сделанной в CSP в метод Signature#update() передавать не заранее вычисленный дайджест, а данные в исходном виде, то подпись проверяется! Т.е. получается, что JCP автоматически и в любом случае вычисляет дайджест с проверяемых данных??? Так ли это? В документации я не нашел информации о том, что при вызове метода Signature#verify() JCP автоматически вычислит дайджест с данных переданных через метод Signature#update(). | ||||
| ||||
Ну да, все правильно. Вы действительно просто подписывали хеш на хеш. В объект подписи в Java передаются данные, а не значение хеша. | ||||