使用图片传输加密数据

图片传输信息

不想被人看见的信息,通过图片传输

项目介绍

为了方便起见,将代码直接写在html中方便查阅。 encode.html,介绍了是如何将数据信息藏在一张图片中 decode.html,介绍了是如何从一张拥有隐藏信息的图片中,把数据给解读出来.

# encode.html加密

<!DOCTYPE html>
<html lang="zh">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>test image save</title>
  <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
</head>

<body>
  <img id="testImg" src="" alt="">
  <div id="container"></div>
  <script>
    // 想要藏起来的数据
    var data = {
      author: 'ifredom',
      data: ["2018-01-04", "cool! boy"]
    }
    // 将JSON对象转换为字节数组
    var strData = JSON.stringify(data)
    var encoder = new TextEncoder('utf-8')
    var unit8array = encoder.encode(strData)
    var charset = encoder.encoding
    var dataSize = Math.ceil(Math.sqrt(unit8array.length / 3))

    // 将字节数组转换为图像数据
    // canvas使用的ImageData对象,需要的是Uint8ClampedArray,目前已有一个 uint8array ,所以需要做一下转化
    // 由于我需要无损格式来存储我的图像数据,因此我选择PNG图片作为输出格式。这也意味着不是将数据存储为RGB,而是将其存储为RGBA。
    // 这里不得不编写代码,将我的3元组字节数组 unit8array 转换为4元组数组 paddedData ,第4个(alpha)组件设置为完全不透明度(255)。
    // 每个像素有一个额外的Alpha通道,因此需要额外的字节。但是经过一些实验后,当alpha通道设置为零时,我遇到了一个与RGB损坏有关的问题,所以直接将Alpha设置为255,完全不透明
    var paddedData = new Uint8ClampedArray(dataSize * dataSize * 4);
    var idx = 0;
    for (var i = 0; i < unit8array.length; i += 3) {
      var subArray = unit8array.subarray(i, i + 3);
      paddedData.set(subArray, idx);
      paddedData.set([255], idx + 3);
      idx += 4;
    }
    console.log(paddedData);

    // 终于得到想要的数据,Uint8ClampedArray字节数组,可以构造我的ImageData对象了。
    var imageData = new ImageData(paddedData, dataSize, dataSize);


    // 绘制图形,将ImageData装入canvas图像中
    var imgSize = 256;
    var canvas = document.createElement('canvas');
    canvas.height = canvas.width = imgSize
    var ctx = canvas.getContext('2d')
    ctx.fillStyle = '#AA0000'
    ctx.fillRect(0, 0, imgSize, imgSize)
    ctx.fillStyle = 'rgb(' + dataSize + ',0,0)';
    ctx.fillRect(0, 0, 1, 1);
    // 将数据填充到图形中
    ctx.putImageData(imageData, 0, 1);

    // 来吧,把图片的下载加上,OK
    var container = document.getElementById('container')
    container.innerHTML =
      `<a id="hiddenLink" href="${canvas.toDataURL()}" download="${canvas.toDataURL()}">下载加密后的文件</a>`
    var img = document.getElementById('testImg').setAttribute('src', canvas.toDataURL())

    // ==============================================
  </script>
</body>

</html>
# decode.html揭秘

<!DOCTYPE html>
<html lang="cn-ZH">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <title>Document</title>
</head>

<body>
  // Uncaught DOMException: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted
  by cross-origin data.
  <script>
    // 这里必须开启一个服务才可以,参考readme~~
    initImg()

    // am.png是一张藏有数据的图片,现在把它夹在进来.
    function initImg() {
      var img = new Image();
      img.onload = function () {
        renderImg(img);
      };
      img.crossOrigin = 'anonymous';
      img.src = 'am.png';
    }

    function renderImg(img) {
      // 创建canvas用来处理图片数据
      var imgSize = img.width;
      var canvas = document.createElement('canvas');
      canvas.width = canvas.height = imgSize;
      var ctx = canvas.getContext('2d');
      // 将图片信息装入canvas
      ctx.drawImage(img, 0, 0);

      // 将像素转换为字节数组
      // 只需读取第一个像素值的数据并抓取第一个字节以获取数据大小
      var headerData = ctx.getImageData(0, 0, 1, 1)
      var dataSize = headerData.data[0]


      // 创建一个足以容纳RGB数据的uint8array,其中RGBA像素的alpha值始终设置为255
      var imageData = ctx.getImageData(0, 1, dataSize, dataSize)
      var paddedData = imageData.data
      var uint8array = new Uint8Array(paddedData.length / 4 * 3)

      // 每4个字节,提取其中前3个字节的值复制到新数组,第四个用来填充的当然是抛弃啦
      var idx = 0
      for (let index = 0; index < paddedData.length - 1; index += 4) {
        var subArray = paddedData.slice(index, index + 3)
        uint8array.set(subArray, idx)
        idx += 3
      }

      // 数组uint8array,其中包含我们所有的数据以及最后的大量使用零填充的数据,零填充数据也需要过滤掉。
      // 因为我们要填充的数据不太多,而数组的长度是固定的,所以要把最后面的零去掉
      // 因此我们需要找到数组中这个零填充结束的位置,从结尾开始遍历数组,直到我们达到第一个非零字节
      var includeBytes = uint8array.length
      for (let j = uint8array.length - 1; j > 0; j--) {
        if (uint8array[j] == 0) {
          includeBytes--
        } else {
          break
        }
      }

      // 解码字节数组
      var data = uint8array.slice(0, includeBytes);
      var result = (new TextDecoder('utf-8')).decode(data);
      console.log(result);

    }
  </script>
</body>

</html>

源码以及详细介绍

github: !https://github.com/ifredom/node-blog/tree/master/project/picture_encryption

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值