spring-projects/spring-security · error · IOException

Expected

Error message

Expected 

What it means

After reading the 4-byte length header, readBigInteger reads exactly l key bytes; if the stream has fewer bytes than the declared length, the blob is malformed and this IOException ('Expected <l> key bytes') is thrown.

Source

Thrown at crypto/src/main/java/org/springframework/security/crypto/encrypt/RsaKeyHelper.java:279

		data[2] = (byte) ((length >> 8) & 0xFF);
		data[3] = (byte) (length & 0xFF);
		stream.write(data);
		stream.write(num.toByteArray());
	}

	private static byte[] readBigInteger(ByteArrayInputStream in) throws IOException {
		byte[] b = new byte[4];

		if (in.read(b) != 4) {
			throw new IOException("Expected length data as 4 bytes");
		}

		int l = ((b[0] & 0xFF) << 24) | ((b[1] & 0xFF) << 16) | ((b[2] & 0xFF) << 8) | (b[3] & 0xFF);

		b = new byte[l];

		if (in.read(b) != l) {
			throw new IOException("Expected " + l + " key bytes");
		}

		return b;
	}

}

View on GitHub (pinned to 96852e8860)

Solutions

  1. Restore the full key from its source (regenerate with ssh-keygen if lost).
  2. Strip all whitespace/newlines from the base64 body before parsing.
  3. Confirm the key's integrity with ssh-keygen -l -f keyfile.
  4. Catch the RuntimeException and inspect getCause() to surface this message to the user.

Example fix

// before
String key = pastedKey.replaceAll("\\s", "").substring(0, 300); // truncated
helper.extractPublicKey(key);
// after
String key = pastedKey.trim();
if (key.split("\\s+")[1].length() >= 372) { // typical 2048-bit ssh-rsa body
    helper.extractPublicKey(key);
}
Defensive patterns

Strategy: validation

Validate before calling

boolean lengthsConsistent(byte[] blob) {
    int off = 11;
    while (off + 4 <= blob.length) {
        int l = ((blob[off] & 0xFF) << 24) | ((blob[off+1] & 0xFF) << 16) | ((blob[off+2] & 0xFF) << 8) | (blob[off+3] & 0xFF);
        if (l < 0 || off + 4 + l > blob.length) return false;
        off += 4 + l;
        if (off == blob.length) return true;
    }
    return false;
}

Try / catch

try {
    RSAPublicKey pk = helper.extractPublicKey(key);
} catch (RuntimeException e) {
    if (e.getCause() != null && e.getCause().getMessage().contains("key bytes")) {
        throw new ConfigException("Declared key length exceeds available bytes — key is truncated or corrupted");
    }
    throw e;
}

Prevention

When it happens

Trigger: The SSH blob declares a field length (e.g. exponent or modulus size) larger than the remaining bytes — truncated base64 or a corrupted/edited key body.

Common situations: Copy/paste truncation of long RSA keys, line-wrapping tools inserting whitespace that broke base64 decoding assumptions, or corrupted uploads of authorized_keys content.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10). Data as JSON: /api/errors/2df643d8da46fd18. Report an issue: GitHub.