Исключения Java: неправильная спецификация ключа и короткое чтение длины DER

Используя функции Base64 из Apache Commons API и работая с DSA, я пытаюсь загрузить открытый ключ с кодировкой base 64 из файла, вот используемый метод

/**
 * Load a base-64 encoded public key in X.509 format
 * @param pkfile the name of the file containing the public key 
 * @return an instance of PublicKey on success or null on failure
 */
public PublicKey loadBase64PublicKey(String pkfile) { 
    PublicKey pub;
    Base64InputStream bis;
    byte[] buffer;

    // load the contents of the pkfile into the buffer
    try {
        bis = new Base64InputStream(new FileInputStream(pkfile));
        buffer = new byte[bis.available()];
        bis.read(buffer);
        bis.close();
    } catch (Exception e) {
        System.err.println(e.toString());
        return null;
    }

    // use a KeyFactory to parse the data
    try {
        KeyFactory kf = KeyFactory.getInstance("DSA");
        pub = kf.generatePublic(new X509EncodedKeySpec(buffer));
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }

    return pub;
}

Основной метод:

public static void main(String args[]) {
    DigitalSignatureA DSA = new DigitalSignatureA();

    // load public key
    PublicKey pubKey;
    pubKey = DSA.loadBase64PublicKey("sign\\pubkey-1.dat");
}   

Однако при вызове метода из main возникает следующая ошибка:

java.security.spec.InvalidKeySpecException: Inappropriate key specification: IOException: Short read of DER length
at sun.security.provider.DSAKeyFactory.engineGeneratePublic(Unknown Source)
at java.security.KeyFactory.generatePublic(Unknown Source)
at DigitalSignatureAssignment.loadBase64PublicKey(DigitalSignatureAssignment.java:147)
at DigitalSignatureAssignment.main(DigitalSignatureAssignment.java:224)

Строка 147 будет pub = kf.generatePublic(new X509EncodedKeySpec(buffer));. Открытый ключ из файла закодирован в X509, но сохранен в кодировке base64, а Base64InputStream декодирует любой ввод.


person cojoe    schedule 08.04.2018    source источник


Ответы (1)


Java InputStream.available() никогда не гарантирует, что сколько (больше) данных существует

Обратите внимание, что хотя некоторые реализации InputStream будут возвращать общее количество байтов в потоке, многие этого не сделают. Никогда нельзя использовать возвращаемое этим методом значение для выделения буфера, предназначенного для хранения всех данных в этом потоке.

и в этом случае с кодеком Commons это даже не попробуй

Возвращает:
0, если InputStream достиг EOF, 1 в противном случае.

Либо выберите для начала достаточно большой размер буфера, либо продолжайте расширять его и читать дальше до EOF, либо и то, и другое одновременно. Или прочитайте файл в память как текст (например, Files.readAllLines или Files.readAllBytes в j8+), а затем декодируйте эту копию в памяти (теперь FWIW j8+ имеет java.util.Base64, и для этого вам не нужен кодек commons-codec)

person dave_thompson_085    schedule 09.04.2018