• Das Erstellen neuer Accounts wurde ausgesetzt. Bei berechtigtem Interesse bitte Kontaktaufnahme über die üblichen Wege. Beste Grüße der Admin

problem mit umwandlung von ArrayBuffer (UInt8Array TextEncoder base64)

Z

zirzofer

Guest
GELÖST


Ich möchte gerne ergebnise aus der window.crypto.subtle.encrypt funktion an meinen server senden. da diese allerdings einen arraybuffer ausgibt, moechte ich das erst zu einem string konvertieren um es anschliessend zb in einer datenbank speichern zu koennen.
hier stosse ich aber auf ein problem, das ich mir nicht erklaeren kann:

Code:
console.log(encrypted); //ArrayBuffer { byteLength: 28 } (sample output from encryption function)
var encryptedAsUint8 = new Uint8Array(encrypted);
console.log(encryptedAsUint8); //Uint8Array [ 25, 235, 161, 121, 221, 61, 132, 15, 161, 17...

var decoded = new TextDecoder("utf-8").decode(encrypted);
console.log(decoded); //�y�=��ͨ˫~���@��UcQ�
var decoded64 = btoa(encodeURIComponent(decoded));
console.log(decoded64); //JTE5JUVGJUJGJUJEeSVFRiVCRiVCRCUzRCVFRiVCRiVCRCUwRiVFRiVCRiVCRCUxMSVDRCVBOCVDQiVBQn4lRUYlQkYlQkQlRUYlQkYlQkQlMDIlN0YlRUYlQkYlQkQlNDAlRUYlQkYlQkQlRUYlQkYlQkRVY1ElRUYlQkYlQkQ=
var encodedAgain = decodeURIComponent(atob(decoded64));
console.log(encodedAgain); //�y�=��ͨ˫~���@��UcQ�
console.log(decoded === encodedAgain); //true


var backToUint8 = new Uint8Array(new TextEncoder("utf-8").encode(encodedAgain));
console.log(backToUint8 === encrypted); //false ??????? 
console.log(backToUint8); //Uint8Array [ 25, 239, 191, 189, 121, 239, 191, 189, 61, 239,... ---> warum enthält das aus dem identischen String erzeugte Array nun unterschiedlichen Inhalt??

PS: gleich selbst der hinweis: das ist ein crosspost von stackoverflow da ich dort keine loesung erhalten habe.
 
Zuletzt bearbeitet:
warum das sich so seltsam verhaelt

weil dein ausgangspuffer vermutlich schon keine gültigen utf8 zeichen enthällt, damit vermutlich schon TextDecoder.decode schief geht, aber vermutlich irgendwas versucht das noch hinzubiegen, was aber als wieder in utf8 gewandelte bytewurst nicht mehr dem ausgangspuffer entspricht.
25 ist ok
ob 235, 161 ein gültiges utf8 zeichen ist wäre nachzuprüfen
121 ist wieder ok
spätestens aber 221, 61 dürfte keins sein, da das 2. byte bei 2byte-zeichen größer als 128 sein muss wenn ich das richtig in erinnerung habe

- - - Aktualisiert - - -

https://de.wikipedia.org/wiki/UTF-8#Algorithmus
192 bis 224: 2 byte zeichen
224 bis 240: 3 byte zeichen
ab 240: 4 byte zeichen
damit ist dein 2. zeichen schon ein 3-bytezeichen
235, 161, 121
wobei 121 nicht passt
 
Warum machst du das mit UTF-8 überhaupt? Lass diesen Schritt doch einfach komplett weg und arbeite nur mit base64. Leider akzeptiert btoa keinen Array - du musst also entweder das base64-Encoding selber schreiben oder den Array vorher in einen String umwandeln:
Code:
var a = new Uint8Array([25, 235, 161, 121, 221, 61, 132, 15, 161, 17]);
var str = a.reduce(function(str, v){
	return str + String.fromCharCode(v);
}, "");
console.log(str, "->" btoa(str));
 
Warum machst du das mit UTF-8 überhaupt? Lass diesen Schritt doch einfach komplett weg und arbeite nur mit base64.
Habe ich anfangs versucht, dann ´gibt es aber probelme mit umlauten und sonderzeichen. hier mal das ganze script:

PHP:
var encode = function(input) {
	//in Base64 umwandeln zur Vermeidung von Problemen mit Sonderzeichen und dann zu Array-Buffer konvertieren
	return new TextEncoder("utf-8").encode(btoa(encodeURIComponent(input).replace(/%([0-9A-F]{2})/g, function(match, p1) {
		return String.fromCharCode("0x" + p1);
	})));
}
var decode = function(input) {
	//zurück in String konvertieren und Base64 dekodieren
	return decodeURIComponent(Array.prototype.map.call(atob(new TextDecoder("utf-8").decode(new Uint8Array(input))), function(c) {
		return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
	}).join(""));
};

var string = "Test mit Umlauten und Sonderzeichen äääpöö#..+&%$";
var ivv = string = uint8array = encode(string);

var usages = ["encrypt", "decrypt", "sign", "verify", "deriveKey", "deriveBits", "wrapKey", "unwrapKey"];



crypto.subtle.importKey(
		"jwk", //can be "jwk" or "raw"
		{ //this is an example jwk key, "raw" would be an ArrayBuffer
			kty: "oct",
			k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE",
			alg: "A256GCM",
			ext: true,
		}, { //this is the algorithm options
			name: "AES-GCM",
		}, false, //whether the key is extractable (i.e. can be used in exportKey)
		["encrypt", "decrypt"] //can "encrypt", "decrypt", "wrapKey", or "unwrapKey"
	)
	.then(function(key) {
		//returns a key object
		console.log(key);
		encrypt(string, key)


	})
	.catch(function(err) {
		console.error(err);
	}); //window.crypto.getRandomValues(new Uint8Array(12)),

var initVect = encode("test");




var encrypt = function(plaintext, key) {
	let encodedPlaintext = new TextEncoder("utf-8").encode(btoa(encodeURIComponent(plaintext).replace(/%([0-9A-F]{2})/g, function(match, p1) {
		return String.fromCharCode("0x" + p1);
	})));
	crypto.subtle.encrypt({
				name: "AES-GCM",
				iv: initVect,
			},
			key,
			encodedPlaintext
		)
		.then(function(encrypted) {
			console.log(encrypted);
			encrypted = new Uint8Array(encrypted);
			console.log("Davor: ", encrypted);

			var decoded = new TextDecoder("utf-8").decode(encrypted);
			console.log("Davor Plain: ", decoded);
			var decoded64 = btoa(encodeURIComponent(decoded));
			console.log("Davor als Base64: ", decoded64);
			var decodedplain = decodeURIComponent(atob(decoded64));
			console.log("Danach als Plain: ", decodedplain);
			console.log(decoded === decodedplain)

			console.info(decoded === decodedplain)

			var c = new Uint8Array(new TextEncoder("utf-8").encode(decoded));
			console.log(c === encrypted);
			console.log(c);


			console.log("Danach: ", encrypted);
			decrypt(encrypted, key);
		})
		.catch(function(e) {
			console.error(e);
		});
}

var decrypt = function(encrypted, key) {
	crypto.subtle.decrypt({
				name: "AES-GCM",
				iv: initVect,
			},
			key,
			encrypted
		)
		.then(function(decrypted) {
			console.log(decode(decrypted));
		})
		.catch(function(e) {
			console.error(e);
		});
};
 
genau das tue ich doch...
keine ahnung was du tust

mit
https://github.com/inexorabletash/text-encoding#non-standard-behavior
kannst du übrigens dein array auch iso8859 codiert erzeugen(warum auch immer das im standard nicht enthalten ist).
allerdings ist hier auch noch einiges im argen.
* wenn du TextDecoder.decode nutzen willst um probelme mit zeichen jenseits der 8-bit zu umschiffen, kann etwas nicht stimmen, da du iso8859 benötigst und nicht utf16 um zeichen größer 8-bit auszushließen.
* String.fromCharCode wie von kkapsner vorgeschlagen, welches elementweise über ein 8-bit-array geht sollte keine zeichen erzeugen welche probleme bei base64 bereitet
 
Zurück
Oben