在 javascript 中反向按位移位

bitwise shifting in reverse in javascript

我想知道如何使以下位移过程反向进行?

chr1 = (enc1 | ((enc2 & 3) << 6));
chr2 = (enc2 >> 2) | ((enc3 & 0x0F) << 4);
chr3 = (enc3 >> 4) | (enc4 << 2);

这基本上是为我正在使用的解码脚本移动位。我想知道有没有办法逆转这个过程,编码而不是解码?

这来自以下以 base64 解码的脚本:

Base64 = {
        _keyStr: ".ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+=",
        decode: function( input ) {
                    var output = "";
                    var hex = "";
                    var chr1, chr2, chr3 = "";
                    var enc1, enc2, enc3, enc4 = "";
                    var i = 0;
                    var base64test = /[^A-Za-z0-9\+\.\=]/g;

                    do {
                        enc1 = this._keyStr.indexOf(input.charAt(i++)) ;
                        enc2 = this._keyStr.indexOf(input.charAt(i++)) ;
                        enc3 = this._keyStr.indexOf(input.charAt(i++)) ;
                        enc4 = this._keyStr.indexOf(input.charAt(i++)) ;

                        chr1 = (enc1 | ((enc2 & 3) << 6));                                                                                                             
                        chr2 = (enc2 >> 2) | ((enc3 & 0x0F) << 4);                                                                                                     
                        chr3 = (enc3 >> 4) | (enc4 << 2);


                        output = output + String.fromCharCode(chr1);
                        if (enc3 != 64) {
                            output = output + String.fromCharCode(chr2);
                        }
                        if (enc4 != 64) {
                            output = output + String.fromCharCode(chr3);
                        }
                        chr1 = chr2 = chr3 = "";
                        enc1 = enc2 = enc3 = enc4 = "";
                    } while (i < input.length);

                    return (output);
                }
}

观察以下计算:

// enc = [0, 1, 0, 0]
chr1 = (0 | ((1 & 3) << 6)) = 64
chr2 = (1 >> 2) | ((0 & 0x0F) << 4) = 0
chr3 = (0 >> 4) | (0 << 2) = 0

// enc = [64, 0, 0, 0]
chr1 = (64 | ((0 & 3) << 6)) = 64
chr2 = (0 >> 2) | ((0 & 0x0F) << 4) = 0
chr3 = (0 >> 4) | (0 << 2) = 0

由于两个输入映射到相同的输出,该函数不是injective,即不能反转。

如果您假设 enc 的所有值都小于 64,您可以反转它:

enc1 = chr1 & 0x3f;
enc2 = (chr1 >> 6) | ((chr2 & 0xf) << 2);
enc3 = (chr2 >> 4) | ((chr3 & 0x3) << 4);
enc4 = chr3 >> 2;

由于 space 的值不是那么大,您可以简单地全部测试它们,就在您的浏览器中:

'use strict';

function _indicate(status) {
  var indicator = document.querySelector('.indicator');
  while (indicator.firstChild) {
    indicator.removeNode(firstChild);
  }
  indicator.setAttribute('class', status);
  indicator.appendChild(document.createTextNode(status));
}

function test(enc1, enc2, enc3, enc4) {
  var chr1 = (enc1 | ((enc2 & 3) << 6));
  var chr2 = (enc2 >> 2) | ((enc3 & 0x0F) << 4);
  var chr3 = (enc3 >> 4) | (enc4 << 2);

  var dec1 = chr1 & 0x3f;
  var dec2 = (chr1 >> 6) | ((chr2 & 0xf) << 2);
  var dec3 = (chr2 >> 4) | ((chr3 & 0x3) << 4);
  var dec4 = chr3 >> 2;

  if ((enc1 !== dec1) || (enc2 !== dec2) || (enc3 !== dec3) || (enc4 !== dec4)) {
    console.log('FAIL');
    console.log('chr ' + chr1 + ', ' + chr2 + ', ' + chr3);
    console.log('Expected/got: ' + enc1 + '/' + dec1 + ', ' + enc2 + '/' + dec2 + ', ' + enc3 + '/' + dec3 + ', ' + enc4 + '/' + dec4);
    _indicate('fail');
    throw new Error('Failed test');
  }
}


for (var enc1 = 0; enc1 < 63; enc1++) {
  for (var enc2 = 0; enc2 < 63; enc2++) {
    for (var enc3 = 0; enc3 < 63; enc3++) {
      for (var enc4 = 0; enc4 < 63; enc4++) {
        test(enc1, enc2, enc3, enc4);
      }
    }
  }
}
_indicate('pass');
.fail {
  background: red;
}
.pass {
  background: green;
}
<div class="indicator"></div>