Jestem w stanie przenieść tablicę bajtów z serwera Java na serwer JavaScript (odbierany jako Int32Array). Dzięki temu chcę móc przesłać PublicKey wygenerowany w Javie i otrzymać go jako CryptoKey w JavaScript.

Klucz publiczny RSA jest generowany w Javie w następujący sposób:

SecureRandom sr = new SecureRandom();
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(2048, sr);
KeyPair kp = generator.generateKeyPair();
PublicKey pKey = kp.getPublic();

To, co próbowałem, to użyć Key#getEncoded(), aby uzyskać klucz publiczny jako tablicę bajtów, przenieść go do JavaScript za pomocą metody aformenetioned, a następnie zaimportować go w ten sposób:

const subtle = window.crypto.subtle;
await subtle.importKey("spki", array, { name: "RSA-OAEP", hash: "SHA-256" }, false, [ "encrypt" ])

Gdzie „array” to Int32Array otrzymany z serwera Java. To jednak nie działa i zawsze otrzymuję nieopisowy wyjątek DOMException stwierdzający „Dane dostarczone do operacji nie spełniają wymagań”. Zrobiłem oczywiste rozwiązywanie problemów, sprawdzając, czy tablica jest taka sama przed i po wysłaniu, zmieniając TypedArray w ArrayBuffer, kodując i dekodując w base64 jako kontrolę poprawności bajtów i próbując różnych algorytmów, ale bezskutecznie.

Niektóre zasoby:

Oto przykładowa tablica bajtów key#getEncoded() zgłoszona przez Javę przed wysłaniem (po wysłaniu jest Int32Array([...]) z tą samą zawartością)

[48, -126, 1, 32, 48, 11, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 10, 3, -126, 1, 15, 0, 48, -126, 1, 10, 2, -126, 1, 1, 0, -44, -97, 125, 40, -104, -77, -56, 30, 64, -51, -44, 35, -91, 83, 43, -92, 1, 104, -7, -71, 61, -111, 74, -17, -43, 96, 47, 5, 71, 57, -23, -80, 12, 23, -89, -5, 18, 56, 32, -125, -48, 115, -126, 45, 71, 73, -53, -68, -104, -95, 18, -76, 21, 22, 122, 26, -89, -128, -118, 99, -65, 89, -81, -120, 72, -85, 20, 44, -119, -38, 4, -1, -69, -105, -70, -52, 126, 58, 86, -9, 4, -55, 104, -81, 21, -91, -128, -101, -82, -15, -1, -4, -13, -116, 48, -91, -60, 81, 111, 53, 126, 91, -46, 16, -5, -99, 73, -40, -99, -24, -46, -75, -99, 48, -67, 92, -92, -78, -115, 76, -35, -51, 75, -56, 70, 56, -10, 13, -108, 56, 79, 34, -22, -123, -91, -12, 9, -21, -32, 22, -88, -79, -13, -35, 61, 24, -115, -93, 40, 46, -88, 5, -105, -69, 82, -57, 10, -15, -91, 21, 53, -60, -31, -102, -63, -35, 71, -72, 50, 2, 37, 93, -70, -87, -110, -69, -10, 88, 51, 118, 30, 45, -11, 74, -92, -109, -10, 102, 79, -128, 14, 61, 94, -100, 69, 97, 56, 38, -14, 29, -85, -78, 2, 31, -127, -107, 86, -16, -114, -7, -83, 31, 77, -120, 77, 73, 114, 38, -124, 31, 116, -83, 39, -36, 85, 92, 86, 52, 22, -90, -47, 101, 16, 94, -16, -95, -33, 68, 112, 88, 94, -47, 121, -83, 3, -80, 111, 21, -42, 65, -101, 72, -126, 4, -83, -11, 2, 3, 1, 0, 1]

Te same dane wyrażone w systemie szesnastkowym

30 82 01 20 30 0B 06 09 2A 86 48 86 F7 0D 01 01 0A 03 82 01 0F 00 30 82 01 0A 02 82 01 01 00 D4 9F 7D 28 98 B3 C8 1E 40 CD D4 23 A5 53 2B A4 01 68 F9 B9 3D 91 4A EF D5 60 2F 05 47 39 E9 B0 0C 17 A7 FB 12 38 20 83 D0 73 82 2D 47 49 CB BC 98 A1 12 B4 15 16 7A 1A A7 80 8A 63 BF 59 AF 88 48 AB 14 2C 89 DA 04 FF BB 97 BA CC 7E 3A 56 F7 04 C9 68 AF 15 A5 80 9B AE F1 FF FC F3 8C 30 A5 C4 51 6F 35 7E 5B D2 10 FB 9D 49 D8 9D E8 D2 B5 9D 30 BD 5C A4 B2 8D 4C DD CD 4B C8 46 38 F6 0D 94 38 4F 22 EA 85 A5 F4 09 EB E0 16 A8 B1 F3 DD 3D 18 8D A3 28 2E A8 05 97 BB 52 C7 0A F1 A5 15 35 C4 E1 9A C1 DD 47 B8 32 02 25 5D BA A9 92 BB F6 58 33 76 1E 2D F5 4A A4 93 F6 66 4F 80 0E 3D 5E 9C 45 61 38 26 F2 1D AB B2 02 1F 81 95 56 F0 8E F9 AD 1F 4D 88 4D 49 72 26 84 1F 74 AD 27 DC 55 5C 56 34 16 A6 D1 65 10 5E F0 A1 DF 44 70 58 5E D1 79 AD 03 B0 6F 15 D6 41 9B 48 82 04 AD F5 02 03 01 00 01

Dziękuję każdemu, kto poświęca czas na pomoc lub odpowiedź!

1
Wasabi Thumbs 5 styczeń 2022, 05:57

1 odpowiedź

Najlepsza odpowiedź

Przede wszystkim działające rozwiązanie: klucz X.509/SPKI zakodowany w formacie DER wygenerowany za pomocą Key#getEncoded() jest zakodowany w Base64, a następnie zaimportowany po stronie JavaScript w następujący sposób:

(async () => {
    const subtle = window.crypto.subtle;
    var keyAB = b642ab("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuuKRgspvg47d4I3pAzCIWKSim2Rs1QeTVE1Hs+P099PkiuMt5dq5GIaIT1DZTYwJrwtUpxnMcr1TNdWGGfovDLJuIRXUFeST1xOD9+rA4FhVZPO/x6ts2TYKiueEq/qPlXREXw8aVq+msw0nYhHFIAAyrtmj7UR6gD3xxl1ghviIycKqUf7rL98b1d6YkYoNW62aIP/u3cJ5v3Fhnth02Cb02M/fX5gvFKJ3Nj2ARbLygZWbO3U09Vs/hnElxE2k1sKxYRqImJdQM04oQOXVVpafZP7eF9/T+YYDxMLcEKAwH9z0fTt9HaL4gyiDWUT02r6qWF7vI85I1jrPLn71mQIDAQAB")

    var key = await subtle.importKey("spki", new Uint8Array(keyAB), { name: "RSA-OAEP", hash: "SHA-256" }, false, [ "encrypt" ])   
    console.log(key)
})();

function b642ab(base64string){
    return Uint8Array.from(atob(base64string), c => c.charCodeAt(0)).buffer;
}

Problem jest spowodowany przez użyty typ Int32Array. Wpisana tablica jest podobnym do tablicy widokiem bazowego ArrayBuffer. W Int32Array każdy element odpowiada 4 bajtom.
Ponieważ Int32Array zawiera te same wartości co Key#getEncoded(), bazowy ArrayBuffer zawiera 4 razy więcej wartości i dlatego nie odpowiada już oryginalnemu kluczowi.

1
Topaco 5 styczeń 2022, 11:48
Hmm, nie do końca. Ta metoda działa dla przykładowego ciągu Base64, który podałeś, ale wypróbuj go na jednym otrzymanym z mojego serwera Java (opublikowany na toptal.com/developers/hastebin/raw/pijowoxuza), to nie działa. Dokładnie ten sam błąd „Dane dostarczone do operacji nie spełniają wymagań”, brak śladu stosu. Jednak bardzo doceniam pomoc!
 – 
Wasabi Thumbs
5 styczeń 2022, 11:58
- Kod zamieszczony w pytaniu generuje klucz publiczny w formacie X.509/SPKI. Jednak klucz zamieszczony w łączu w komentarzu jest kluczem publicznym w formacie PKCS#1 i dlatego w rzeczywistości nie można go wygenerować za pomocą kodu Java! Czy w Twoim pytaniu brakuje jakichś istotnych informacji? Zauważ, że WebCrypto nie obsługuje formatu PKCS#1. Musisz więc wygenerować klucz bezpośrednio w formacie X.509/SPKI (np. z opublikowanym kodem Java) lub przekonwertować klucz PKCS#1 do formatu obsługiwanego przez WebCrypto.
 – 
Topaco
5 styczeń 2022, 12:33
Tak, masz rację. Zmieniłem kod od czasu mojego oryginalnego postu, próbując go uruchomić. Odwróciłem to, a potem działało dobrze. Mój błąd! Twoja wiedza i pomoc są bardzo cenione.
 – 
Wasabi Thumbs
5 styczeń 2022, 12:52