• UTF8编码字节流错误小析


          对于对称加密,首先生成字节流形式的key与iv,之后对指定字符串进行加密,然后将key与iv转换为字符串传输到另一端,另一端再将字符串转换回字节流完成解密工作.在key与iv的字节流与字符串之间的转换中如果选用Utf8编码,则可能会让转换回的二进制流与之前的字节流不一致.代码如下:

    byte[] bytes = new byte[]{146, 174, 27, 74, 223, 159, 52, 180};
    string s = Encoding.UTF8.GetString(bytes);
    Console.WriteLine(s);
    byte[] bytes2 = Encoding.UTF8.GetBytes(s);
    Console.WriteLine(bytes2);

          你会发现,bytes2的内容变为了:{239,191,189,239,191,189,27,74,223,159,52,239,191,189}.

          从表面看,其将146, 174, 180三个数扩展成了 239,191,189.但毫无规律可寻,223比它们都大,保持了下来,27之类的比他们小,也保持了下来,甚至是159,在它们中间,也保存了下来.说双数变吧,74是双数,却也保持了下来.后来经过不懈努力,终于大致弄懂原因了.

          1.什么是字符编码.

          字符编码,就是将计算机里记录的0与1以一定的规则转换成人类的字符,如英文或中文,是计算机表达字符的方式,其本质就是一个翻译,.目前计算机有多种表式方式,比如ASCII之类的.不同的方式对字节基数要求不一样,有的固定字节/字符的,如Ascii是一字节一字符,Gb2312是两字节一字符,有的是不固定字节/字符的,如Utft8,就从一字节到四字节表示一个字符.不同的方式翻译方式也不一样,比如对于字节{84,128,26,144},如果使用Gb2312翻译,就是"联通"两字,使用Utf8翻译,就是乱码"T�□�"

          2.Utf8的特殊性

          字节流的组合有无数种,但能被字符集识别的只是其中的一部分.就像人的嗓子可以发出很多种声音,但只有26个声母与5个韵母的组合才能发音成人类语言.Utf8也不例外.Utf8的编码规则如下:

    Unicode编码(16进制) UTF-8 字节流(二进制)
    000000 – 00007F 0xxxxxxx
    000080 – 0007FF 110xxxxx 10xxxxxx
    000800 – 00FFFF 1110xxxx 10xxxxxx 10xxxxxx
    010000 – 10FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

          可以看到

          1.以0,110,1110,11110开头的字节,可以被识别

          2.如果以10开头,则要求前一个字节必须以10,110,1110,11110开头

          3.如果以10开头且前一个也以10开头,则再前一个必须以10,1110,11110开头

          4.如果以10开头且前一个以10开头且再前一个也以10开头,则再前一个必须以11110开头

          5.不能被识别的字节,每一个会转换成三个字节{11101111,10111111,10111101},也就是239,191,189

          3.解析问题

          上面所提到的字节流所对应的二进制流如下:

    146 10010010
    174 10101110
    27 00011011
    74 01001010
    223 11011111
    159 10011111
    52 00110100
    180 10110100

          可以看到,27,74,223,52满足规则1,159满足规则2,而146,174,180一个也不满足,各个被转换成了239,191,189.所以,最终的结果就是如上所示了.

          使用Ascii,Utf7, Utf32编码都会有不同程度的变样,理由同Utf8.

          4.正确的做法

          虽然经过我的实验,使用Unicode编码可以完全还原,但将字节流转换成字符串的正确做法是进行Base64编码.不同与其它的语言编码,这是专门用于字节流与节符串转换的编码.使用Convert类的ToBase64String方法与FromBase64String方法即可完成全部功能.Base64的相关知识请自行谷哥.

          参考的文章:

          中文编码杂谈

          base64

  • 相关阅读:
    AJAX
    Aliyun服务器配置Redis
    Aliyun服务器配置MySQL
    Python基础之迭代器详解
    Python基础之函数
    Flask入门--URL
    认识Web
    肖知兴:企业的底层逻辑与企业家的突破(下)
    建造者模式(Bulider模式)详解
    为什么我强烈推荐你用枚举来实现单例模式
  • 原文地址:https://www.cnblogs.com/ljzforever/p/2950308.html
Copyright © 2020-2023  润新知