Perl Cryptology:使用打包和解包功能加密/解密 ASCII 字符

Posted

技术标签:

【中文标题】Perl Cryptology:使用打包和解包功能加密/解密 ASCII 字符【英文标题】:Perl Cryptology: Encrypting/Decrypting ASCII chracters with pack and unpack functions 【发布时间】:2012-07-17 04:10:53 【问题描述】:

我需要帮助弄清楚这两个子例程如何工作以及它们返回什么值或数据结构。这是代码的最小表示:

#!/usr/bin/perl
use strict; use warnings;

# an array of ASCII encrypted characters
my @quality = ("C~#p)eOA`/>*", "DCCec)ds~~", "*^&*"); # for instance

# input the quality
# the '@' character in front deferences the subroutine's returned array ref 
my @q = @unpack_qual_to_phred(@quality);

print pack_phred_to_qual(\@q) . "\n";

sub unpack_qual_to_phred
    my ($qual)=@_;
    my $upack_code='c' . length($qual);
    my @q=unpack("$upack_code",$qual);
    for(my $i=0;$i<@q;$i++)
        $q[$i]-=64;
    
    return(\@q);


sub pack_phred_to_qual
    my ($q_ref)=@_;
    @q=@$q_ref;
    for(my $i=0;$i<@q;$i++)
        $q[$i]+=64;
    
    my $pack_code='c' . int(@q);
    my $qual=pack("$pack_code",@q);

    return ($qual);



1;

据我了解,unpack_qual_to_phread() 子例程显然会解密存储在@quality 中的 ASCII 字符元素。该子例程读入一个包含 ASCII 字符元素的数组。数组的每个元素都经过处理并明显解密。然后,子例程返回一个包含解密数组元素的数组 ref。我非常了解但是我对 Perl 函数 packunpack 并不是很熟悉。我也无法在网上找到任何好的例子。

我认为pack_phred_to_qual 子例程将质量数组 ref 转换回 ASCII 字符并打印出来。

谢谢。非常感谢任何帮助或建议。另外,如果有人能提供一个简单的例子来说明 Perl 的 packunpack 函数是如何工作的,那也会有所帮助。

【问题讨论】:

【参考方案1】:

计算长度是不必要的。这些功能可以简化为

sub unpack_qual_to_phred  [ map $_ - 64, unpack 'c*', $_[0] ] 
sub pack_phred_to_qual  pack 'c*', map $_ + 64, @ $_[0]  

在加密术语中,这是一个疯狂的简单替换密码。它只是从每个字符的字符数中减去 64。可以写成

sub encrypt  map $_ - 64, @_ 
sub decrypt  map $_ + 64, @_ 

打包/解包根本不考虑加密/解密;这只是一种遍历每个字节的方式。

【讨论】:

我仍在试图弄清楚unpackpack 函数是如何工作的。在我上面发布的示例中,unpack("c12", "C~#p)eOA'/&gt;*") 处理的第一个元素将值存储到@q 中,你能告诉我存储在@q 中的第一个元素的值吗?我正在努力解决这个问题。 对于字节 67,即 ASCII 中的“C”,unpack C 返回 67。 关于unpack("c12", C~#p)eOA'/&gt;*c12 是模板,C~#p)eOA/>*` 是表达式。模板c12 的真正含义是什么? c12 表示cccccccccccc。也可以写成c*。对接下来的 11 个字节重复上述操作。 TEMPLATE 不“工作”。它告诉unpackpack 要做什么。详细信息在文档中。 EXPRESSION 你在说什么?类似的文档中没有使用该术语。【参考方案2】:

这很简单,就像打包一样。 Is 正在调用 unpack("c12", "C~#p)eOA/>*)`,它依次获取每个字母并找到该字母的 ascii 值,然后从该值中减去 64(嗯,减去 64 是后处理步骤,与 pack 无关)。所以字母“C”是ascii 67,67-64是3。因此,该函数的第一个值是3。接下来是“~”,即ascii 126。126-64是62。接下来是#,即ascii 35 , 35-64 是 -29 等等。

从您的脚本生成的完整数字集是:

3,62,-29,48,-23,37,15,1,32,-17,-2,-22

“加密”步骤只是简单地反转了这个过程。将 64 相加,然后转换为 char。

【讨论】:

关于unpack("c12", C~#p)eOA'/&gt;*c12 是模板,C~#p)eOA/>*` 是表达式。模板c12 的真正含义是什么?【参考方案3】:

这不是您问题的完整答案,但您是否阅读过perlpacktut?或者perldoc 上的pack/unpack 文档?这些可能会大大帮助您理解。

编辑:

这是一种简单的思考方式:假设您有一个 4 字节的数字存储在内存中,1234。如果它是一个 perl 标量 $num,那么

pack('s*', $num)

会回来

π♦

或“1234”的实际内部存储值。因此pack() 将标量值视为字符串,并将其转换为数字的实际二进制表示(您会看到打印出的“pi-diamond”,因为那是该数字的 ASCII 表示)。反之,

unpack('s*', "π♦")

将返回字符串“1234”。


unpack_qual_to_phred() 子例程的 unpack() 部分可以简化为:

my @q = unpack("c12", "C~#p)e0A`/>*");

这将返回一个 ASCII 字符对列表,每对对应于第二个参数中的一个字节。

【讨论】:

感谢@Joe 的链接。我今天早些时候浏览了这些网页,但我认为他们提供的示例让我更加困惑。 谢谢你的例子。我有两个问题:二进制表示是否与 ASCII 表示相同?另一个问题:在您提供的示例中unpack('s*', "π♦")'s*' 是模板。 TEMPLATE 在 unpack 函数中是如何工作的?它如何告诉函数格式化π♦ 不,二进制表示不同。假设存储在字节 RAM 中的实际位是 01010100。十进制值为 84。但该字节的 ASCII 表示是“T”(参见 www.asciitable.com)。 RAM 字节的实际值是相同的——我们只是改变了解释它的方式。 该模板的工作原理与某些 C 标准库函数(如 printf())中的“格式”字符串基本相同。它告诉 pack() 或 unpack() 如何 转换数据。所以“s*”的意思是“把第二个参数当作一个有符号的 16 位值”。那只是“s”; "*" 告诉 pack()/unpack() 在第二个 arg 字符串中有可变数量的字符,所以把它们都拿走。 例如,如果我在上面使用pack('H*', $num),$num 将被视为十六进制数。所以pack('H*', $num) 会返回实际的十六进制值 0x1234,或十进制的 4660。同样,unpack('H*', $num) 将再次将 1234 视为十六进制字符串 0x1234,然后将其解释为 ASCII,返回“31323334”(查看您的 ASCII 表,您会注意到“31”==“1” ASCII、“32”==“2”等)。

以上是关于Perl Cryptology:使用打包和解包功能加密/解密 ASCII 字符的主要内容,如果未能解决你的问题,请参考以下文章

使用python中的struct模块打包和解包可变长度数组/字符串

如何使用 ctypes 打包和解包(结构 <-> str)

什么是打包和解包以及扩展打包数据

从R中的列表中打包和解包元素

SSE/SSE2 指令的打包和解包数据?

当我打包和解包浮点数时,如何消除浮点不准确性?