wowok
Version:
Wowok Blockchain TypeScript API
1 lines • 5.85 kB
JavaScript
import{generateX25519KeyPair,x25519DH,hkdfChainKey,hkdfMessageKey,aesGcmEncrypt,aesGcmDecrypt,concatBytes}from'./crypto.js';import{MessageType,PQError,PQErrorCode}from'./types.js';function encodeHeader(a){const b=new Uint8Array(0x20+0x4+0x4);b['set'](a['dhPublicKey'],0x0);const c=new DataView(b['buffer']);return c['setUint32'](0x20,a['previousSendingCount'],![]),c['setUint32'](0x24,a['messageCount'],![]),b;}function decodeHeader(a){const b=a['slice'](0x0,0x20),c=new DataView(a['buffer'],a['byteOffset'],a['byteLength']),d=c['getUint32'](0x20,![]),e=c['getUint32'](0x24,![]);return{'dhPublicKey':b,'previousSendingCount':d,'messageCount':e};}function makeSkipKey(a,b){const c=new Uint8Array(a['length']+0x4);return c['set'](a,0x0),new DataView(c['buffer'])['setUint32'](a['length'],b,![]),Buffer['from'](c)['toString']('base64');}export function initRatchet(a,b,c,d,e){return{'rootKey':a,'sendingChainKey':b,'sendingMessageCount':0x0,'receivingChainKey':c,'receivingMessageCount':0x0,'ourDHKeyPair':d,'peerDHPublicKey':e,'previousSendingCount':0x0,'skipMessageKeys':new Map()};}export function ratchetEncrypt(a,b){const c=cloneRatchetState(a),{messageKey:d,nextChainKey:e}=hkdfMessageKey(c['sendingChainKey']);c['sendingChainKey']=e;const f={'dhPublicKey':c['ourDHKeyPair']['publicKey'],'previousSendingCount':c['previousSendingCount'],'messageCount':c['sendingMessageCount']},g=encodeHeader(f),{ciphertext:h,iv:i,tag:j}=aesGcmEncrypt(d,b,g),k=concatBytes(g,i,j,h);return c['sendingMessageCount']+=0x1,{'message':{'type':MessageType['NORMAL_MESSAGE'],'body':k},'newState':c};}export function ratchetDecrypt(a,b){const c=0x20+0x4+0x4;if(b['length']<c+0xc+0x10)throw new PQError(PQErrorCode['DECRYPTION_FAILED'],'Message\x20body\x20too\x20short');const d=b['slice'](0x0,c),e=decodeHeader(d),f=b['slice'](c,c+0xc),g=b['slice'](c+0xc,c+0xc+0x10),h=b['slice'](c+0xc+0x10),i=cloneRatchetState(a);let j;if(i['peerDHPublicKey']&&Buffer['from'](e['dhPublicKey'])['equals'](Buffer['from'](i['peerDHPublicKey']))){if(e['messageCount']<i['receivingMessageCount']){j=trySkippedMessageKeys(i,e);if(!j)throw new PQError(PQErrorCode['DECRYPTION_FAILED'],'Message\x20key\x20not\x20found\x20for\x20old\x20message');}else{while(i['receivingMessageCount']<e['messageCount']){const {messageKey:n,nextChainKey:o}=hkdfMessageKey(i['receivingChainKey']),p=makeSkipKey(e['dhPublicKey'],i['receivingMessageCount']);i['skipMessageKeys']['set'](p,n),i['receivingChainKey']=o,i['receivingMessageCount']+=0x1;}const {messageKey:l,nextChainKey:m}=hkdfMessageKey(i['receivingChainKey']);j=l,i['receivingChainKey']=m,i['receivingMessageCount']+=0x1;}}else{j=trySkippedMessageKeys(i,e);if(!j){const q=dhRatchetStep(i,e);Object['assign'](i,q['newState']),j=q['messageKey'];}}const k=aesGcmDecrypt(j,h,f,g,d);return{'plaintext':k,'newState':i};}function dhRatchetStep(a,b){a['previousSendingCount']=a['sendingMessageCount'];const c=x25519DH(a['ourDHKeyPair']['privateKey'],b['dhPublicKey']),{rootKey:d,chainKey:e}=hkdfChainKey(a['rootKey'],c),f=generateX25519KeyPair(),g=x25519DH(f['privateKey'],b['dhPublicKey']),{rootKey:h,chainKey:i}=hkdfChainKey(d,g),{messageKey:j}=hkdfMessageKey(e);return{'messageKey':j,'newState':{'rootKey':h,'sendingChainKey':e,'sendingMessageCount':0x0,'receivingChainKey':i,'receivingMessageCount':0x1,'ourDHKeyPair':f,'peerDHPublicKey':b['dhPublicKey'],'previousSendingCount':b['previousSendingCount']}};}function trySkippedMessageKeys(a,b){const c=makeSkipKey(b['dhPublicKey'],b['messageCount']),d=a['skipMessageKeys']['get'](c);if(d)return a['skipMessageKeys']['delete'](c),d;return null;}function cloneRatchetState(a){return{'rootKey':new Uint8Array(a['rootKey']),'sendingChainKey':new Uint8Array(a['sendingChainKey']),'sendingMessageCount':a['sendingMessageCount'],'receivingChainKey':new Uint8Array(a['receivingChainKey']),'receivingMessageCount':a['receivingMessageCount'],'ourDHKeyPair':{'publicKey':new Uint8Array(a['ourDHKeyPair']['publicKey']),'privateKey':new Uint8Array(a['ourDHKeyPair']['privateKey'])},'peerDHPublicKey':a['peerDHPublicKey']?new Uint8Array(a['peerDHPublicKey']):null,'previousSendingCount':a['previousSendingCount'],'skipMessageKeys':new Map(a['skipMessageKeys'])};}export function serializeRatchetState(a){const b={};for(const [c,d]of a['skipMessageKeys']){b[c]=Buffer['from'](d)['toString']('base64');}return{'rootKey':Buffer['from'](a['rootKey'])['toString']('base64'),'sendingChainKey':Buffer['from'](a['sendingChainKey'])['toString']('base64'),'sendingMessageCount':a['sendingMessageCount'],'receivingChainKey':Buffer['from'](a['receivingChainKey'])['toString']('base64'),'receivingMessageCount':a['receivingMessageCount'],'ourDHPrivateKey':Buffer['from'](a['ourDHKeyPair']['privateKey'])['toString']('base64'),'ourDHPublicKey':Buffer['from'](a['ourDHKeyPair']['publicKey'])['toString']('base64'),'peerDHPublicKey':a['peerDHPublicKey']?Buffer['from'](a['peerDHPublicKey'])['toString']('base64'):null,'previousSendingCount':a['previousSendingCount'],'skipMessageKeys':b};}export function deserializeRatchetState(a){const b=new Map();for(const [c,d]of Object['entries'](a['skipMessageKeys'])){b['set'](c,new Uint8Array(Buffer['from'](d,'base64')));}return{'rootKey':new Uint8Array(Buffer['from'](a['rootKey'],'base64')),'sendingChainKey':new Uint8Array(Buffer['from'](a['sendingChainKey'],'base64')),'sendingMessageCount':a['sendingMessageCount'],'receivingChainKey':new Uint8Array(Buffer['from'](a['receivingChainKey'],'base64')),'receivingMessageCount':a['receivingMessageCount'],'ourDHKeyPair':{'publicKey':new Uint8Array(Buffer['from'](a['ourDHPublicKey'],'base64')),'privateKey':new Uint8Array(Buffer['from'](a['ourDHPrivateKey'],'base64'))},'peerDHPublicKey':a['peerDHPublicKey']?new Uint8Array(Buffer['from'](a['peerDHPublicKey'],'base64')):null,'previousSendingCount':a['previousSendingCount'],'skipMessageKeys':b};}