Changeset - 90018dea7eac
[Not reviewed]
default
0 2 0
Laman - 5 years ago 2019-07-02 14:46:42

base64 encoding
2 files changed with 64 insertions and 0 deletions:
0 comments (0 inline, 0 general)
spec/test/utilSpec.js
Show inline comments
 
/* global expect */
 

	
 
describe("Util",function(){
 
  let cryptoJS=require("../../dist/main.js");
 
	let util=cryptoJS.util;
 
	let utf=[ // https://tools.ietf.org/html/rfc3629#page-8
 
		["",[]],
 
		["abc",[97,98,99]],
 
		["å",[195,165]],
 
		["🚅",[240,159,154,133]],
 
		["žír",[0xc5,0xbe,0xc3,0xad,114]],
 
		["A\u2262\u0391.",[0x41,0xE2,0x89,0xA2,0xCE,0x91,0x2E]],
 
		["\uD55C\uAD6D\uC5B4",[0xED,0x95,0x9C,0xEA,0xB5,0xAD,0xEC,0x96,0xB4]],
 
		["\ud84c\udfb4",[0xf0,0xa3,0x8e,0xb4]]
 
	];
 
	let base64=[
 
		[[],""],
 
		[[102],"Zg=="],
 
		[[102,111],"Zm8="],
 
		[[102,111,111],"Zm9v"],
 
		[[102,111,111,98],"Zm9vYg=="],
 
		[[102,111,111,98,97],"Zm9vYmE="],
 
		[[102,111,111,98,97,114],"Zm9vYmFy"]
 
	];
 
	
 
	describe("bytes2int32s",function(){
 
		it("should pack bytes into 32b integers",function(){
 
			expect(util.bytes2int32s([])).toEqual([]);
 
			expect(util.bytes2int32s([0])).toEqual([0]);
 
			expect(util.bytes2int32s([1])).toEqual([1]);
 
			expect(util.bytes2int32s([0x12,0x34,0x56,0x78,0x9a])).toEqual([0x78563412,0x9a]);
 
		});
 
	});
 
	
 
	describe("str2utf8",function(){
 
		it("should encode a String into bytes in UTF-8",function(){
 
			utf.forEach(couple=>expect(util.str2utf8(couple[0])).toEqual(couple[1]));
 
		});
 
	});
 
	
 
	describe("utf82str",function(){
 
		it("should decode a String from UTF-8 bytes",function(){
 
			utf.forEach(couple=>expect(util.utf82str(couple[1])).toEqual(couple[0]));
 
		});
 
	});
 
	
 
	
 
	describe("bytes2base64",function(){
 
		it("should correctly encode bytes into base64",function(){
 
			base64.forEach(couple=>expect(util.bytes2base64(couple[0])).toEqual(couple[1]));
 
		});
 
	});
 
	
 
	describe("base642bytes",function(){
 
		it("should correctly decode bytes from base64",function(){
 
			base64.forEach(couple=>expect(util.base642bytes(couple[1])).toEqual(couple[0]));
 
		});
 
	});
 
});
src/util.js
Show inline comments
 
export const MASK=0xffffffff;
 

	
 
export function zeroPad(arr,length){
 
	return arr.concat((new Array(length)).fill(0)).slice(0,length);
 
}
 

	
 
export function bytes2int32(arr){
 
	return arr.reduce((acc,b,i)=>acc|b<<(i*8));
 
}
 

	
 
export function bytes2int32s(arr){
 
	let res=[];
 
	for(let i=0;i<arr.length;i+=4){
 
		res.push(bytes2int32(arr.slice(i,i+4)));
 
	}
 
	return res;
 
}
 

	
 
/**
 
 * Converts a 32 bit integer into 4 bytes in little endian order.
 
 */
 
export function int322bytes(x){
 
	let res=[];
 
	for(let i=0;i<4;i++){
 
		res.push(x&0xff);
 
		x>>>=8;
 
	}
 
	return res;
 
}
 

	
 
/**
 
 * Converts a 32 bit integer into 4 bytes in big endian order.
 
 */
 
export function int322bytesBE(x){
 
	let res=int322bytes(x);
 
	res.reverse();
 
	return res;
 
}
 

	
 
export function int32s2bytes(arr){
 
	return arr.map(int322bytes).reduce((acc,bytes)=>acc.concat(bytes));
 
}
 

	
 
export function bytes2hex(arr){
 
	return arr.map(x=>x.toString(16).padStart(2,"0")).join("");
 
}
 

	
 
export function str2utf8(s){
 
	let res=[];
 
	let c=s.codePointAt(0);
 
	for(let i=0; c!==undefined; i++,c=s.codePointAt(i)){
 
		if(c<0x80){res.push(c);}
 
		else if(c<0x800){
 
			res.push(0b11000000|(c>>>6));
 
			res.push(0b10000000|(c&0b111111));
 
		}
 
		else if(c<0x10000){
 
			res.push(0b11100000|(c>>>12));
 
			res.push(0b10000000|((c>>>6)&0b111111));
 
			res.push(0b10000000|(c&0b111111));
 
		}
 
		else{
 
			res.push(0b11110000|(c>>>18));
 
			res.push(0b10000000|((c>>>12)&0b111111));
 
			res.push(0b10000000|((c>>>6)&0b111111));
 
			res.push(0b10000000|(c&0b111111));
 
		}
 
		if(c>0xffff){i++;} // skip surrogate
 
	}
 
	return res;
 
}
 

	
 
export function utf82str(arr){
 
	let res=[];
 
	for(let i=0;i<arr.length;i++){
 
		let x=arr[i];
 
		if(x<=0b1111111){res.push(x);}
 
		else if(x<=0b11011111){
 
			let a=x&0b11111;
 
			let b=arr[++i]&0b111111;
 
			res.push(a<<6|b);
 
		}
 
		else if(x<=0b11101111){
 
			let a=x&0b1111;
 
			let b=arr[++i]&0b111111;
 
			let c=arr[++i]&0b111111;
 
			res.push(a<<12|b<<6|c);
 
		}
 
		else{
 
			let a=x&0b111;
 
			let b=arr[++i]&0b111111;
 
			let c=arr[++i]&0b111111;
 
			let d=arr[++i]&0b111111;
 
			res.push(a<<18|b<<12|c<<6|d);
 
		}
 
	}
 
	return res.map(x=>String.fromCodePoint(x)).join("");
 
}
 

	
 
const mapping="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("");
 
const remapping=new Array(128);
 
mapping.forEach((c,i)=>{remapping[c.charCodeAt(0)]=i;});
 

	
 
export function bytes2base64(byteArr){
 
	let arr=byteArr.concat();
 
	let out=[];
 
	let rem=(3-arr.length%3)%3;
 
	for(let i=0;i<rem;i++){arr.push(0);} // pad array to a multiple of 3
 
	
 
	for(let i=0;i<arr.length;i+=3){ // encode 3 bytes into 4 characters
 
		out.push(mapping[arr[i]>>>2&63]);
 
		out.push(mapping[((arr[i]&3)<<4)+(arr[i+1]>>>4&15)]);
 
		out.push(mapping[((arr[i+1]&15)<<2)+(arr[i+2]>>>6&3)]);
 
		out.push(mapping[arr[i+2]&63]);
 
	}
 
	
 
	for(let i=0;i<rem;i++){out.pop();}
 
	for(let i=0;i<rem;i++){out.push("=");}
 

	
 
	return out.join("");
 
}
 

	
 
export function base642bytes(str){
 
	let out=[];
 
	
 
	for(let i=0;i<str.length;i+=4){
 
		let b1=remapping[str.charCodeAt(i)];
 
		let b2=remapping[str.charCodeAt(i+1)];
 
		let b3=remapping[str.charCodeAt(i+2)];
 
		let b4=remapping[str.charCodeAt(i+3)];
 
		
 
		out.push((b1<<2)+(b2>>4&3));
 
		out.push(((b2&15)<<4)+(b3>>2&15));
 
		out.push(((b3&3)<<6)+b4);
 
	}
 
	
 
	for(let i=1; i<3&&str[str.length-i]=="="; i++){out.pop();}
 

	
 
	return out;
 
}
0 comments (0 inline, 0 general)