DSA (Digital Signature Algorithm) представляет собой алгоритм электронной подписи, основанный на дискретном логарифмировании в конечных полях. Его ключевая идея заключается в том, что вычисление подписи легко выполняется при наличии закрытого ключа, но практически невозможно восстановить закрытый ключ или подделать подпись без него.
DSA опирается на параметры домена:
Процесс формирования подписи состоит из двух вычислений:
Пара (r, s) и есть цифровая подпись сообщения m.
Проверка выполняется через:
Подпись считается корректной, если v = r.
Библиотека Jsrsasign работает с криптографическими объектами через ASN.1 и PEM-кодирование. DSA-ключи обычно представлены в формате:
Внутри Jsrsasign используется пространство имён KEYUTIL
и KJUR.crypto.
Jsrsasign позволяет создавать ключевые пары с помощью
KEYUTIL.generateKeypair.
Пример генерации:
const kp = KEYUTIL.generateKeypair("DSA", 1024);
const prv = kp.prvKeyObj;
const pub = kp.pubKeyObj;
console.log(KEYUTIL.getPEM(prv, "PKCS8PRV"));
console.log(KEYUTIL.getPEM(pub));
Параметр 1024 указывает длину ключа (на практике чаще используют 2048 или выше, хотя DSA исторически ограничен стандартами q = 160/224/256 бит).
Основной интерфейс для подписи —
KJUR.crypto.Signature.
Для DSA используется алгоритм вида SHA256withDSA или
SHA1withDSA (устаревший вариант).
const sig = new KJUR.crypto.Signature({ "alg": "SHA256withDSA" });
sig.init(prv);
sig.updateString("Сообщение для подписи");
const signature = sig.sign();
console.log(signature);
Подпись возвращается в формате Base64 или HEX в зависимости от настроек.
Для верификации используется тот же класс Signature, но
инициализируется публичным ключом.
const sig = new KJUR.crypto.Signature({ "alg": "SHA256withDSA" });
sig.init(pub);
sig.updateString("Сообщение для подписи");
const isValid = sig.verify(signature);
console.log(isValid);
Если сообщение или подпись изменены, результат будет
false.
DSA не подписывает данные напрямую. Всегда используется хеш-функция.
Jsrsasign автоматически применяет выбранный алгоритм:
Важно учитывать соответствие между длиной q и хеш-функцией:
Несоответствие может привести к ошибкам или снижению криптографической стойкости.
В Jsrsasign подпись DSA кодируется как ASN.1 структура:
DSA-Signature ::= SEQUENCE {
r INTEGER,
s INTEGER
}
При экспорте в Base64 получается DER-представление. Это важно при взаимодействии с внешними системами (OpenSSL, Java KeyStore).
Подписи, созданные Jsrsasign, обычно совместимы с OpenSSL, если:
Пример экспорта ключа:
const pem = KEYUTIL.getPEM(pub);
Этот PEM можно импортировать в OpenSSL без дополнительных преобразований.
1. Использование SHA-1
SHA-1 считается криптографически слабым. Многие реализации уже запрещают его использование.
2. Неправильный размер ключа
DSA требует строгого соответствия между p, q и выбранным алгоритмом хеширования.
3. Повторное использование nonce k
Если одно значение k используется для двух разных сообщений, закрытый ключ x может быть восстановлен.
Это критическая ошибка реализации алгоритма.
4. Неверная кодировка подписи
Base64 и HEX часто путаются при передаче между системами.
Jsrsasign позволяет подписывать не только строки, но и бинарные
данные через updateHex:
sig.updateHex("deadbeefcafebabe");
const signature = sig.sign();
Это важно при работе с протоколами, где данные представлены в байтовом виде.
Для длинных сообщений применяется потоковое обновление:
sig.init(prv);
sig.updateString("часть 1");
sig.updateString("часть 2");
sig.updateString("часть 3");
const signature = sig.sign();
Хеширование выполняется инкрементально, без загрузки всего сообщения в память сразу.
Jsrsasign поддерживает JSON Web Key формат:
const keyObj = KEYUTIL.getKey(jwk);
DSA может быть представлен в JWK как:
{
"kty": "DSA",
"p": "...",
"q": "...",
"g": "...",
"y": "..."
}
Однако поддержка DSA в JWK ограничена в современных спецификациях JWT.
DSA обладает рядом особенностей:
Jsrsasign реализует стандартный DSA без модификаций, что обеспечивает совместимость с классическими системами, но не включает современных расширений вроде deterministic nonce (RFC 6979 применяется чаще к ECDSA).
DSA в Jsrsasign чаще встречается в:
Современные системы чаще переходят на RSA-PSS или ECDSA, однако Jsrsasign сохраняет DSA для обратной совместимости и анализа существующих данных.
При верификации Jsrsasign не выбрасывает исключение при неверной подписи. Вместо этого возвращается логическое значение:
true — подпись корректнаfalse — подпись не совпадаетЭто позволяет использовать проверку в цепочках условной логики без try/catch.