**This is an old revision of the document!**

组件:数据卡

此组件由数据卡提供。

组件名:data

1级回调函数

  • crc32(data:string):string
    计算数据的CRC-32哈希值。结果为二进制格式。
  • decode64(data:string):string
    对数据进行base64解码。
  • encode64(data:string):string
    对数据进行base64编码。结果为二进制格式。
  • md5(data:string):string
    计算数据的MD5哈希值。结果为二进制格式。
  • sha256(data:string):string
    计算数据的SHA2-256哈希值。结果为二进制格式。
  • deflate(data:string):string
    对数据用deflate算法压缩。
  • inflate(data:string):string
    对数据用infalte算法解压。
  • getLimit():number
    返回单次可被传递给此扩展卡其他函数的最大数据大小。

2级回调函数

  • encrypt(data:string, key:string, iv:string):string
    使用给定密钥以及初始向量IV(最好为随机)对数据进行AES加密。
  • decrypt(data:string, key:string, iv:string):string
    使用给定密钥以及初始向量IV对数据进行AES解密。
  • random(len:number):string
    生成长度为 len 的随机二进制字符串。

3级回调函数

  • generateKeyPair([bitLen:number]):table, table
    生成一对可用于多种加密算法的公钥与私钥。可选的第二个参数代表密钥长度,值可为256或384。
    密钥类型包括“ec-public”和“ec-private”。密钥可以使用key.serialize():string来序列化。密钥中还包含一个函数key.isPublic():boolean
  • ecdsa(data:string, key:userdata[, sig:string]):string or boolean
    不给定签名则使用给定私钥生成数据的一份签名。若给定了签名则功能为使用公钥、先前生成的签名字符串以及原字符串验证签名。
  • ecdh(privateKey:userdata, publicKey:userdata):string
    使用第一个参数给出的用户私钥与第二个参数给出的用户公钥,生成一个Diffie-Hellman共享密钥。密钥基本关系的样例为: ecdh(userA.private, userB.public) == ecdh(userB.private, userA.public)
  • deserializeKey(data:string, type:string):table
    将密钥从字符串形式转化为其特有形式。

样例

此扩展卡可用于向其他在游戏中或在现实中的人发送加密数据。既然我们有能力创建密钥对和Diffie-Hellman共享密钥,那么我们就可以与这些人建立加密连接。

使用密钥对进行加密时的基本原则为:

预备工作:

  • (下列工作需要接收者完成)
  • 生成一个公钥(rPublic)与一个私钥(rPrivate)。
  • **若不能进行自动密钥交换,则你需要将rPublic手动传给发送者

发送者必须:

  • ***读取接收者的公钥(rPublic),将其解序列化并重构密钥对象。
  • 生成一个公钥(sPublic)和一个私钥(sPrivate)。
  • *用rPublicsPrivate生成加密密钥。
  • 生成一个初始向量(IV)。
  • 使用sPublic.serialize()sPublic转化为字符串
  • ***用serialization(串连)运行库将数据序列化,然后使用加密密钥和IV将其加密。
  • 串连并发送信息,其中有明文形式的sPublic与IV。

接收者必须:

  • 读取发送者的私钥(rPrivate),将其解序列化并重构密钥对象。
  • 接收信息,并使用serialization(串连)运行库将其解序列化。然后使用data.deserializeKey()解序列化sPublic
  • *使用sPublicrPrivate生成解密密钥。
  • 使用解密密钥和IV来解密信息。
  • 解序列化解密后的信息。

注*:上文中使用了“加密密钥”和“解密密钥”两个术语。这两个密钥的每一字节都对应相同。这是因为这两个密钥都是使用ecdh()函数生成的。

注**:上文说你需要将rPublic手动传给发送者。但是在使用握手协议的系统中情况并非如此。例如,发送者会让接收者知道自己的存在,然后接收者会回复给发送者一个公钥(可能还有附加信息,例如密钥长度)。为简单起见,以下示例将不涵盖握手协议的功能。

注***:上文与下文的示例说你需要将密钥和信息序列化/解序列化。总体来说,在你将数据(尤其是二进制形式的)写入文件或通过网络传输前串连它们是有益的。序列化能保证二进制数据“有结尾”,使你的脚本或shell读取时更加安全。

若要发送加密数据:

snippet.lua
local serialization  = require("serialization")
local component      = require("component")
 
--此表包含了要发送到接收方电脑的数据。
--表中还有信息头,供接收方用来解密数据。
local __packet =
{
    header =
    {
        sPublic    = nil,
        iv         = nil
    },
 
    data = nil
}
 
--读取公钥文件。
local file = io.open("rPublic","rb")
 
local rPublic = file:read("*a")
 
file:close()
 
--将公钥解序列化为二进制形式。
local rPublic = serialization.unserialize(rPublic)
 
--重建公钥对象。
local rPublic = component.data.deserializeKey(rPublic,"ec-public")
 
--为此会话生成一个公钥与一个私钥。
local sPublic, sPrivate = component.data.generateKeyPair(384)
 
--生成一个加密密钥。
local encryptionKey = component.data.md5(component.data.ecdh(sPrivate, rPublic))
 
--将信息头中值'iv'设定为一个随机生成的16位数字字符串。
__packet.header.iv = component.data.random(16)
 
--将信息头中值'sPublic'设定为一个字符串。
__packet.header.sPublic = sPublic.serialize()
 
--待加密的数据。
__packet.data = "lorem ipsum"
 
--数据被序列化并被加密了。
__packet.data = component.data.encrypt(serialization.serialize(__packet.data), encryptionKey, __packet.header.iv)
 
--为简单起见,此样例中的电脑使用连接卡(ocdoc.cil.li/item:linked_card:zh)
component.tunnel.send(serialization.serialize(__packet))

若要接收加密数据:

snippet.lua
local serialization = require("serialization")
local component     = require("component")
local event         = require("event")
 
--读取私钥。
local file = io.open("rPrivate","rb")
 
local rPrivate = file:read("*a")
 
file:close()
 
--将私钥解序列化。
local rPrivate = serialization.unserialize(rPrivate)
 
--重建私钥对象。
local rPrivate = component.data.deserializeKey(rPrivate,"ec-private")
 
--使用event.pull()以接收来自发送者的信息。
local _, _, _, _, _, message = event.pull("modem_message")
 
--将信息解序列化。
local message = serialization.unserialize(message)
 
--从信息中获取公钥并解序列化。
local sPublic = component.data.deserializeKey(message.header.sPublic,"ec-public")
 
--生成解密密钥。
local decryptionKey = component.data.md5(component.data.ecdh(rPrivate, sPublic))
 
--使用解密密钥和IV来解密message.data中的加密数据
local data = component.data.decrypt(message.data, decryptionKey, message.header.iv)
 
--解序列化解密后的数据。
local data = serialization.unserialize(data)
 
--输出解密后的数据。
print(data)

目录