Extract the 32-byte Ed25519 seed from various secret formats: - byte[] of exactly 32 bytes: used directly - byte[] longer than 32: take last 32 bytes (common PEM/PKCS#8 format) - String: base64 decode, then take last 32 bytes (matches TS: Base64.unarmor(secret).slice(16))
(Object secret)
| 599 | * - String: base64 decode, then take last 32 bytes (matches TS: Base64.unarmor(secret).slice(16)) |
| 600 | */ |
| 601 | private static byte[] extractEd25519Seed(Object secret) { |
| 602 | byte[] raw; |
| 603 | if (secret instanceof byte[] b) { |
| 604 | raw = b; |
| 605 | } else if (secret instanceof String s) { |
| 606 | // Accept PEM-armored PKCS#8 (the common shape: -----BEGIN PRIVATE KEY-----\n...base64...\n-----END PRIVATE KEY-----) |
| 607 | // alongside raw base64. Without the PEM branch the literal hyphens in the |
| 608 | // armor lines trip Base64.getDecoder() with "Illegal base64 character 2d". |
| 609 | if (s.contains("-----BEGIN PRIVATE KEY-----")) { |
| 610 | raw = decodePemBody(s, "-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----"); |
| 611 | } else if (s.contains("-----BEGIN EC PRIVATE KEY-----")) { |
| 612 | raw = decodePemBody(s, "-----BEGIN EC PRIVATE KEY-----", "-----END EC PRIVATE KEY-----"); |
| 613 | } else if (s.contains("-----BEGIN RSA PRIVATE KEY-----")) { |
| 614 | raw = decodePemBody(s, "-----BEGIN RSA PRIVATE KEY-----", "-----END RSA PRIVATE KEY-----"); |
| 615 | } else { |
| 616 | // Plain base64; tolerate optional whitespace/newlines callers may have left in. |
| 617 | raw = Base64.getMimeDecoder().decode(s); |
| 618 | } |
| 619 | } else if (secret instanceof java.util.List<?> list) { |
| 620 | // arraySlice returns List<Byte> — convert to byte[] |
| 621 | raw = new byte[list.size()]; |
| 622 | for (int i = 0; i < list.size(); i++) { |
| 623 | Object elem = list.get(i); |
| 624 | if (elem instanceof Number n) raw[i] = n.byteValue(); |
| 625 | } |
| 626 | } else { |
| 627 | throw new IllegalArgumentException("Ed25519 secret must be byte[], base64 String, or List<Byte>, got: " + secret.getClass().getName()); |
| 628 | } |
| 629 | if (raw.length == 32) { |
| 630 | return raw; |
| 631 | } |
| 632 | if (raw.length > 32) { |
| 633 | // Extract last 32 bytes (seed portion of PKCS#8 or PEM-decoded key) |
| 634 | byte[] seed = new byte[32]; |
| 635 | System.arraycopy(raw, raw.length - 32, seed, 0, 32); |
| 636 | return seed; |
| 637 | } |
| 638 | throw new IllegalArgumentException("Ed25519 secret too short: " + raw.length + " bytes (need 32)"); |
| 639 | } |
| 640 | |
| 641 | // ==================================================== |
| 642 | // CRC32 |
no test coverage detected