@@ -17,6 +17,7 @@ import {
1717 Uint8ArrayTostring ,
1818 GetRandomIndex ,
1919 getStep ,
20+ i2osp ,
2021} from "./Misc.js" ;
2122import { pbkdf2 } from "@noble/hashes/pbkdf2.js" ;
2223import { sha256 } from "@noble/hashes/sha2.js" ;
@@ -383,3 +384,128 @@ export function Decrypt(Data, key, AdvancedEncObj = null) {
383384 return Data ;
384385 }
385386}
387+
388+ /**
389+ * 基于 SHA-256 的 MGF1 实现
390+ *
391+ * @param {Uint8Array } seed - 输入的随机种子
392+ * @param {number } maskLen - 需要生成的掩码目标长度 (字节数)
393+ * @returns {Uint8Array } - 生成的指定长度的伪随机掩码
394+ */
395+ function mgf1_sha256 ( seed , maskLen ) {
396+ const hLen = 32 ; // SHA-256 的输出长度固定为 32 字节 (256 bits)
397+
398+ // RFC 8017 规定: 掩码长度不能超过 2^32 * hLen
399+ // 在 JS 中处理超大文件时要注意内存限制,通常不会触发这个上限
400+ if ( maskLen > 2 ** 32 * hLen ) {
401+ throw new Error ( "Mask too long" ) ;
402+ }
403+
404+ // 预先分配最终输出的内存空间
405+ const mask = new Uint8Array ( maskLen ) ;
406+
407+ // 计算需要循环调用哈希函数的次数 (向上取整)
408+ const iterations = Math . ceil ( maskLen / hLen ) ;
409+
410+ let offset = 0 ; // 记录当前已经填充到 mask 的字节位置
411+
412+ for ( let counter = 0 ; counter < iterations ; counter ++ ) {
413+ // 1. 将计数器转换为 4 字节的大端序字节串 C
414+ const C = i2osp ( counter ) ;
415+
416+ // 2. 拼接 seed 和 C (即 RFC 中的 seed || C)
417+ const dataToHash = new Uint8Array ( seed . length + 4 ) ;
418+ dataToHash . set ( seed , 0 ) ;
419+ dataToHash . set ( C , seed . length ) ;
420+
421+ // 3. 计算拼接后数据的 SHA-256 哈希值
422+ // 【注意】这里调用你的自定义/高效 SHA-256 库
423+ const hashBlock = sha256 ( dataToHash ) ;
424+
425+ // 4. 将哈希块拷贝到最终的 mask 数组中
426+ // 最后一次循环可能不需要完整的 32 字节,计算剩余需要的字节数
427+ const bytesToCopy = Math . min ( hLen , maskLen - offset ) ;
428+
429+ // 使用 subarray 提取需要的字节,并通过 set 写入目标位置
430+ mask . set ( hashBlock . subarray ( 0 , bytesToCopy ) , offset ) ;
431+
432+ offset += bytesToCopy ;
433+ }
434+
435+ return mask ; // 输出生成的掩码流
436+ }
437+
438+ /**
439+ * 基于 SHA-256 的 AONT(全有或全无转换)
440+ *
441+ * @param {Uint8Array } Data 原始数据
442+ * @returns {Uint8Array } AONT处理后数据
443+ */
444+ export function EnAONT ( Data ) {
445+ let Seed = new Uint8Array ( 32 ) ;
446+
447+ for ( let i = 0 ; i < 32 ; i ++ ) {
448+ //获取随机种子
449+ Seed [ i ] = GetRandomIndex ( 256 ) ;
450+ }
451+
452+ //生成掩码,使用mgf1算法,配合SHA256
453+ let Mask = mgf1_sha256 ( Seed , Data . byteLength ) ;
454+
455+ // 将掩码和原始数据执行异或
456+ let MaskedData = new Uint8Array ( Data . byteLength ) ;
457+
458+ for ( let i = 0 ; i < Data . byteLength ; i ++ ) {
459+ MaskedData [ i ] = Data [ i ] ^ Mask [ i ] ;
460+ }
461+
462+ //计算异或后数据的哈希
463+ let MaskedDataHash = sha256 ( MaskedData ) ;
464+
465+ //将异或后数据的哈希,和种子本身执行异或,得到控制块。
466+ let ControlBlock = new Uint8Array ( 32 ) ;
467+
468+ for ( let i = 0 ; i < Seed . byteLength ; i ++ ) {
469+ ControlBlock [ i ] = Seed [ i ] ^ MaskedDataHash [ i ] ;
470+ }
471+
472+ //把控制块和异或后数据拼接在一起。
473+ let Result = new Uint8Array ( MaskedData . byteLength + ControlBlock . byteLength ) ;
474+
475+ Result . set ( MaskedData , 0 ) ;
476+ Result . set ( ControlBlock , MaskedData . byteLength ) ;
477+
478+ return Result ;
479+ }
480+
481+ /**
482+ * 基于 SHA-256 的 AONT(全有或全无转换) 逆处理函数
483+ *
484+ * @param {Uint8Array } Data AONT处理后数据
485+ * @returns {Uint8Array } 原始数据
486+ */
487+ export function DeAONT ( Data ) {
488+ let MaskedData = Data . subarray ( 0 , - 32 ) ;
489+ let ControlBlock = Data . subarray ( - 32 ) ;
490+
491+ //计算异或后数据的哈希
492+ //如果有任何一丁点数据没有成功传输,则此哈希是错误的,因此,还原出的消息种子也是错误的,因此,还原出的消息也是错误的。
493+ let MaskedDataHash = sha256 ( MaskedData ) ;
494+
495+ //计算消息种子
496+ let Seed = new Uint8Array ( 32 ) ;
497+ for ( let i = 0 ; i < Seed . byteLength ; i ++ ) {
498+ Seed [ i ] = ControlBlock [ i ] ^ MaskedDataHash [ i ] ;
499+ }
500+
501+ //计算掩码
502+ let Mask = mgf1_sha256 ( Seed , MaskedData . byteLength ) ;
503+
504+ let Result = new Uint8Array ( MaskedData . byteLength ) ;
505+
506+ for ( let i = 0 ; i < MaskedData . byteLength ; i ++ ) {
507+ Result [ i ] = MaskedData [ i ] ^ Mask [ i ] ;
508+ }
509+
510+ return Result ;
511+ }
0 commit comments