spring-projects/spring-security · error · IOException

Expected length data as 4 bytes

Error message

Expected length data as 4 bytes

What it means

readBigInteger reads a 4-byte big-endian length header from the SSH key blob stream. If fewer than 4 bytes remain, the blob is truncated/malformed and this IOException is thrown (often surfacing as the message-less RuntimeException at line 243).

Source

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

		}
	}

	private static void writeBigInteger(ByteArrayOutputStream stream, BigInteger num) throws IOException {
		int length = num.toByteArray().length;
		byte[] data = new byte[4];
		data[0] = (byte) ((length >> 24) & 0xFF);
		data[1] = (byte) ((length >> 16) & 0xFF);
		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. Supply the complete, unmodified key string including the full base64 body.
  2. Verify the key with ssh-keygen before use.
  3. Ensure the algorithm token is 'ssh-rsa' so blob layout expectations match.
  4. Handle the wrapped IOException via getCause() to give users a meaningful message.

Example fix

// before
String body = "AAAAB"; // truncated base64
helper.extractPublicKey("ssh-rsa " + body);
// after
String body = Files.readString(Path.of("id_rsa.pub")).split(" ")[1]; // complete base64
helper.extractPublicKey("ssh-rsa " + body);
Defensive patterns

Strategy: validation

Validate before calling

boolean hasFullBlob(String base64Body) {
    try {
        byte[] b = Base64.getDecoder().decode(base64Body);
        if (b.length < 15) return false;
        int l = ((b[11] & 0xFF) << 24) | ((b[12] & 0xFF) << 16) | ((b[13] & 0xFF) << 8) | (b[14] & 0xFF);
        return 11 + 4 + l <= b.length;
    } catch (IllegalArgumentException ex) { return false; }
}

Try / catch

try {
    RSAPublicKey pk = helper.extractPublicKey(key);
} catch (RuntimeException e) {
    if (e.getCause() instanceof IOException) {
        throw new ConfigException("SSH key blob truncated: " + e.getCause().getMessage());
    }
    throw e;
}

Prevention

When it happens

Trigger: Parsing an SSH-RSA blob that ends right after the prefix or between fields — i.e. the decoded base64 payload is shorter than the SSH wire structure requires.

Common situations: Partially copied .pub key content, keys that were base64-decoded twice or incorrectly, or non-RSA blob formats (e.g. ed25519 bodies) whose layout misaligns parsing.

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/97500f15b556eb18. Report an issue: GitHub.