Как рассчитать отпечаток пальца из открытого ключа SSH RSA в Java?

Как заголовок, Как рассчитать отпечаток пальца из открытого ключа SSH RSA в Java? Я получил объект rsaPublicKey из sample.pub и рассчитал отпечаток пальца с помощью библиотеки Apache Commons Codec. DigestUtils.sha256Hex(rsaPublicKey.getEncoded()); Но у меня другой отпечаток пальца при использовании команды ssh-keygen ssh-keygen -E sha256 -lf sample.pub sample.pub, как показано ниже ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAsuVPKUpLYSCNVIHD+e6u81IUznkDoiOvn/t56DRcutRc4OrNsZZ+Lmq49T4JCxUSmaT8PeLGS/IC946CNQzFwMh++sVoc19UUkZtRaDgiYn+HkYk8VW4IFI1dKfXomKSbX/lB+ohzLzXLVP2/UJgfBmdaE10k+6b+/Yd8YGXIeS8/Z9zToHPo0ORNSGIolgq3xMXUtfAOK/0KC6IFc/FuvuOSAG1UWup91bcm5GSXv4BWWjgFtOxCLIknYjsDah4qfrP8Olp5eUDhn/65xRcZsmRXoYe1ylhlSjJoPDFWXVs9npwqQmi3JaZtgg7xJxMu1ZcdpYxoj280zM9/6w1Lw==

Есть ли способ обойтись? У меня есть отпечаток пальца, и мне нужен ключ RSA. Это возможно ?

Juan Rivillas 16.10.2018 15:47

Это невозможно. отпечаток пальца рассчитывается с помощью хэш-функции. Если вы знаете, что такое хеш, вы бы не задавали такой вопрос.

linc01n 18.10.2018 07:52
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
4
2
6 785
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Ваша основная проблема заключается в том, что Кодирование в стиле XDR, используемый SSH для открытого ключа, который OpenSSH использует для вычисления отпечатка пальца, не совпадает с кодировкой, используемой криптографией Java, которая представляет собой формат DER ASN.1, определенный X.509, формально называемый SubjectPublicKeyInfo. На самом деле я очень удивлен, что вы смогли прочитать файл OpenSSH .pub на Java; нет прямого способа сделать это. См. Многочисленные существующие Q по этому поводу на ssh-keygen и openssl предоставляют два разных открытых ключа (раскрытие: мое), но при быстрой проверке я не думаю, что кто-то из них является Java, поэтому вам нужно сделать что-то вроде:

byte[] n = rsapubkey.getModulus().toByteArray(); // Java is 2sC bigendian
byte[] e = rsapubkey.getPublicExponent().toByteArray(); // and so is SSH
byte[] tag = "ssh-rsa".getBytes(); // charset very rarely matters here
ByteArrayOutputStream os = new ByteArrayOutputStream();
DataOutputStream do = new DataOutputStream(os);
do.writeInt(tag.length); do.write(tag);
do.writeInt(e.length); do.write(e);
do.writeInt(n.length); do.write(n);
byte[] encoded = os.toByteArray();
// now hash that (you don't really need Apache) 
// assuming SHA256-base64 (see below)
MessageDigest digest = MessageDigest.getInstance("SHA256");
byte[] result = digest.digest(encoded);
String output = Base64.getEncoder().encodeToString(result);

(Кроме того: спасибо linc01n за обнаружение ошибки - я стараюсь всегда компилировать перед публикацией, и я не уверен, как я это пропустил.)

Вторая проблема заключается в том, что OpenSSH никогда не отображал отпечатки SHA256 в шестнадцатеричном формате. Первоначально он использовал отпечатки пальцев MD5 в шестнадцатеричном формате с двоеточиями; в 6.8 он по умолчанию переключился на SHA256 в base64 (с использованием традиционного алфавита, а не «URLsafe», предпочитаемого JSON), хотя вы все еще можете получить старую форму (в ssh используйте -oFingerprintHash=md5 или эквивалентную настройку; в ssh-keygen -l используйте -E md5). Определите, какие из них вы хотите, и запрограммируйте соответственно.

Или, если у вас есть файл .pub, просто прочтите второе поле одной строки, разделенное пробелами, преобразуйте из base64 в byte[], хешируйте его и отобразите.

что, если кодировка платформы по умолчанию - UTF-16? Тогда "ssh-rsa" кодируется неправильно.

President James K. Polk 28.06.2018 01:59

"Фиксированный" :-) :-)

dave_thompson_085 28.06.2018 05:16

Ха-ха, хорошо, ты выиграл.

President James K. Polk 28.06.2018 13:40

Я предлагаю обновить имя переменной "do" на что-нибудь, кроме ключевого слова :)

David Blevins 14.04.2021 11:44

Используйте это для вычисления отпечатка пальца из вашего открытого ключа:

    /**
     * Calculate fingerprint
     *
     * @param publicKey public key
     * @return fingerprint
     */
    public static String calculateFingerprint(String publicKey) {
        String derFormat = publicKey.split(" ")[1].trim();
        MessageDigest messageDigest = null;
        try {
            messageDigest = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException("Could not get fingerprint", e);
        }
        byte[] digest = messageDigest.digest(Base64.getDecoder().decode(derFormat));
        final StringBuilder toRet = new StringBuilder();
        for (int i = 0; i < digest.length; i++) {
            if (i != 0) toRet.append(":");
            int b = digest[i] & 0xff;
            String hex = Integer.toHexString(b);
            if (hex.length() == 1) toRet.append("0");
            toRet.append(hex);
        }
        return toRet.toString();
    }

Это даст вам тот же результат, что и:

ssh-keygen -E md5 -l -f id_rsa.pub

Другие вопросы по теме