当前页面位置: » 丰搜网 » 文档中心 » 详细内容
utf-7 邮件安全的 unicode 转换编码
本备忘录状态:
本文为因特网社区提供信息。本文没有指定任何因特网标准。分发本文不受限制。
摘要 unicode标准,2.0版本, 以及iso/iec 10646-1联合定义了一种字符集,它包含了世界上大多数可书写的字符系统。(后文都直接用unicode一词)。 事实上,因特网邮件(std 11, rfc 822)目前所支持的仅仅是7-bit的ascii字符集。mime(rfc 2045到2049)扩展了网络邮件以支持不同的媒体类型和字符集,也因此能够在邮件信息里支持unicode了。虽然它确实提供了随着时间而增加的字符集注册的方法,但mime既没有把unicode定义为容许的字符集,也没有说明它要怎么编码。 本文档描述了一种unicode的转换编码,它只使用7-bit的ascii字节,并且意图在文件由us-ascii表中字符组成的限定条件下,对人来说是易读的。还说明了在mime的内容中怎么使用这种转换编码(rfc 1641“在mime中使用 unicode”)。
起因 虽然存在着其他的unicode转换格式,并且也足以在这样的环境下使用(最明显的就是utf-8,还有utf-2 or utf-fss),但他们都有一个缺点,就是他们使用了128-255这一范围对unicode编码,超过了us-ascii的范围。因此,在邮件环境中,8位字节必须要被编码。这要求让文本经历两次连续的编码,让us-ascii范围以外的字符有一个显著的扩展,这使得非英文的使用者处于非常不利的地步。例如,使用utf-8和mime中的quoted-printable内容编码方式一起处理,让us-ascii字符出现在一个字节里,但其 它的字符可能需要9个字节。
概述 utf-7把unicode字符编码为us-ascii的字节,并且用替换序列编码超出范围(0-127)的字符。为了这个目的,us-ascii 表里的一个字符就要保留作为替换字符使用。大多邮件网关和系统不能处理完整的us-ascii字符集(例如那些基于ebcdic的),所以utf-7包含了在us-ascii用于编码的预留,以便所有的邮件系统都能兼容。utf-7应该一般用在7-bit传输的环境中,比如邮件。其他的环境中unicode或者utf-8还是 首选的。参见rfc 1641,“在mime中使用unicode”整体描述了在mime中unicode转换编码的使用。
定义 首先,定义unicode: 16-bit字符集,unicode,由"unicode标准,2.0版本"所定义。这套字符集与国际标准组织的编码iso/iec 10646-1一致。 编码后形式为ucs-2;子集为300;实现等级为3,包含对10646+的前7个修正。 注:unicode 2.0 还进一步说明了这些字符在iso标准组织以外的使用和交互。事实上,一个有效的10646序列就是一个有效的unicode序列,反之也是;unicode 协会提供对序列的解析,而iso标准组织却一直没有。 然后,定义一些us-ascii字符子集: 集合d:(直接字符)包含如下的字符(取自rfc 1521,附录b,在rfc 2045中不再出现了): 大写字母a-z,小写字母a-z,和10个数字0-9,和后面的9个特殊字符(注意:"+"和"-"遗漏了) 字符 ascii & unicode值 (十进制)
'' 39
( 40
) 41
, 44
- 45
. 46
/ 47
: 58
? 63 集合o: (可选的直接字符) 包含如下的字符: (注意 "\" 和 "~" 遗漏了): 字符 ascii & unicode值 (十进制)
! 33
" 34
# 35
$ 36
% 37
& 38
* 42
; 59
< 60
= 61
> 62
@ 64
[ 91
] 93
^ 94
_ 95
'' 96
{ 123
124
} 125 基本原理:有两个字符 "\" 和 "~" 被遗漏了是因为在ascii表中他们经常被重新定义变量值。 集合b: (更改过的base64) (rfc 2045)定义的base64字母表中的字符,除了衬垫字符:"=" (十进制值为 61)。 基本原理: 衬垫字符 "=" 被排除了是因为utf-7被设计用来在报头字段中使用,就如rfc 2047中的集合4。 因为rfc 2047编码中唯一易读的编码就是"q",(基于rfc 2045''s quoted printable),所以"="不适合使用(没有很多的转义序列)。这很不幸,但是却不可避免。其实,"=" 字符在utf-7中也可以作为转义字符使用,如果不是使用"+"。 注:所有us-ascii在unicode中都是用同样的值,补0扩展到16 bits。
utf-7 定义: 一个utf-7流用如下方式使用7-bit us-ascii字节表示16-bit unicode字符:
- 规则1:(直接编码) 上面的集合d中的unicode字符可以直接的编码为ascii的等价物。集合o中的字符可以有随意的直接编码为ascii的等价物,但要记得其中的很多的字符在报头字段是不合法的,或者不能正确的穿过邮件网关;
- 规则2:(unicode替换编码) 通过在前面加上转换字符"+"(us-ascii字符十进制值为43),任何一个unicode序列都可以使用集合b中的字符编码。"+"意味着后面的字节将被作为更改过的base64字母表中的元素解析,直到遇到一个不是字母表中的字符为止。这些字符中包含控制字符,比如回车和换行;因此,一个unicode转换序列总是在一行上结束。作为一个特殊的情形,如果序列结束于一个"-"字符(us-ascii值45),那么那个字符就要被关注;其他的结束字符不用关心,而且可以正常处理;
- 注意:如果跟在转换字符后的第一个字符就是"-",那么一个多余的必须被加上,以便结束转换序列,所以真正的"-"不是它关心的;
- 基本原理:一个结束字符在如下的情形是必须的:在更改的base64序列的下一个字符是集合b中的部分,或者本身就是一个结束字符。通过界定编码的序列也可以增强可读性。作为特定情形,序列"+-"可以用来编码字符"+"。一个"+"字符之后立即跟着的字符若不是集合b的成员或者"-",就是一个形式有误的序列;
对unicode使用更改的base64编码时候,可以首先转换unicode的16bit的数量值为一个字节流。通过把成对中的一个当作单独的值以后,就会转换为字节对。奇数个字节的的文本是错误的形式,iso1646 字符超过可设定地址范围的部分转换为字节对后也无法编码。
- 基本原理:iso/iec 10646-1:1993(e)说明了当ucs2形式被字节流序列化时,哪个字节在前面。选定一种用来发送的规范格式,在一般网络应用中也是遵循的;
- 基本原理:iso 10646和unicode标准中代码点定位的策略是一个同步一致的字 符表。如果字节对超过了iso10646可寻址范围,就无法对代码点定 位了。
然后,对字节流进行编码时使用了"更改的base64编码"算法(定义于rfc 2045),更改中去掉了衬垫字符"="。在编码时候,增加了代替的"0 bits"以便衬垫base64编码字符的边界。在解码时,在"更改的base64编码"序列最后的一些bits,如果不能组成一个完整的 16-bit的unicode字符,那么就会被丢弃。如果丢弃的bits不是0,那么这个编码序列就是有格式错误的。
- 基本原理:在对更改的 base64 进行编码时,不使用衬垫字符"=",因为就象上文提及的,它与在 rfc 2047 中将它用做 "q 内容传输编码" 的转义字符相冲突;
- 规则3: 空格 (十进制 32),tab (十进制 9),回车(十进制 13),和换行(十进制 10)字符可以直接使用ascii等价字符表示。事实上,应该注意到mime传输编码也有使用这些字符的规则。如果使用并不遵循rfc 822的限制,必须要使用mime编码而不是7bit或者8bit的一些编码,比如quoted-printable,binary,或者base64。
鉴于给定的一组规则,unicode字符可以经由规则1或者规则3编码,一个字符占用一字节;然后其他的unicode字符用规则2编码,一个字符占用平均(2 + 2/3)个字节,加上一个转换开关字节用来进入"更改的base64编码",加一个可选的转换跳出字节。 例如:unicode序列 "a<not identical to><alpha>." (十进制: 0041,2262,0391,002e) 可以被编码如下: a+imidkq. 例如:unicode序列 "hi mom -<white smiling face>-!" (十进制: 0048, 0069, 0020, 004d, 006f, 006d, 0020, 002d, 263a,002d, 0021) 可以被编码如下: hi mom -+jjo--! 例如:unicode序列 用汉语表示日文 "nihongo" (十进制: 65e5,672c,8a9e) 可以被编码如下: +zevnliqe-
在mime中使用utf-7字符集 utf-7字符集对邮件传输是
安全的,因此可以应用于mime中任何内容的编码(除非出现了对行长度和行中断的强制约束)。特定的,7-bit的编码用于主体, "q内容编码"用于报头的情况也可以使用。mime字符集的标签是utf-7,这一点对大于等于2.0版本的unicode很重要。 例子:这是一个mime消息的片段,包含了一段unicode序列: "hi mom <white smiling face>!" (十进制 0048,0069, 0020, 004d, 006f, 006d, 0020, 263a, 0021)。content-type: text/plain; charset=utf-7 hi mom +jjo-! 例子:这是一个mime消息的片段,包含了一段用汉语表示日语词 "nihongo" 的 unicode 序列: (十进制: 65e5, 672c, 8a9e)。content-type: text/plain; charset=utf-7 +zevnliqe- 例子: 这是一个mime消息的片段 ,包含了一段unicode序列: "a<not identical to><alpha>." (十进制: 0041, 2262, 0391, 002e)content-type: text/plain; charset=utf-7 a+imidkq. 例子: 这是一个mime消息的片段,包含了一段unicode序列: "item 3 is <pound sign>1." (十进制 0049, 0074, 0065, 006d, 0020, 0033, 0020, 0069, 0073, 0020, 00a3, 0031, 002e)。content-type: text/plain; charset=utf-7 item 3 is +akm-1. 注意:为了和"可能不支持unicode与mime的系统"达到最好的互用性,在准备邮件传输正文的时候,"行中断"应该遵守网络惯例。这意味着行应该很短而且要使用smtp的crlf来标记结束。unicode的行分隔符(十进制 2028)和段分隔符 (十进制 2029)应该被替换为smtp的行中断。理想的情况,这应该由一个理解 unicode的用户代理透明的处理。