前段时间在尝试使用不同的语言使用到腾讯的 tc-tea 实现,因此造了一堆轮子。

最开始写的是 C++ 实现,后来改为纯 C 版本,此后根据需要改写了 Rust、Go、JS、PHP 版本。

因为 TEA 的块大小刚好是 8 字节,因此在移植到 Rust 的时候开始尝试使用 u64 来表示其状态。

C

纯 C 语言的实现,GitHub 仓库

需要自行管理内存,用起来相对麻烦。

Rust

纯 Rust 语言的实现。GitHub 仓库 | crates.io

加入到 Cargo.toml[dependencies] 中:

tc_tea = "0.2"

使用:

use tc_tea;

fn hello_tc_tea() {
    let key = b"12345678ABCDEFGH";
    let encrypted = tc_tea::encrypt(&"hello", &key).unwrap();
    let decrypted = tc_tea::decrypt(&encrypted, &key).unwrap();
    assert_eq!("hello", std::str::from_utf8(&decrypted).unwrap());
}

Go

纯 Go 语言的实现。GitHub 仓库

从 Rust 代码移植过来。因为申请内存很方便,这个实现会申请新的内存空间来存储返回数据。

go get github.com/jixunmoe-go/[email protected]

使用案例:

package main

import (
	"bytes"
	"github.com/jixunmoe-go/tc_tea"
	"log"
)

func main() {
	key := []byte("12345678ABCDEFGH")
	encrypted, err := tc_tea.Encrypt([]byte("hello world"), key)
	if err != nil {
		log.Fatal(err)
	}
	decrypted, err := tc_tea.Decrypt(encrypted, key)
	if err != nil {
		log.Fatal(err)
	}
	if !bytes.Equal(decrypted, []byte("hello world")) {
		log.Fatal("decrypted != []byte(\"hello world\")")
	}
}

JavaScript

TypeScript 的实现,支持 Node,带类型提示。GitHub 仓库

没有原生 u64 类型支持,因此使用的还是 Uint8Array 来存储数据。

安装:

npm i tc_tea

使用:

import assert from 'node:assert';
import { decrypt } from 'tc_tea';

const fromHex = (str: string) => Uint8Array.from(Array.from(str.matchAll(/../g), (x) => parseInt(x[0], 16)));
const decoder = new TextDecoder();
const data = fromHex('86ebcc7fa8a354f03fa7575e160b2d09c2238ccc13345a9d');
const result = decoder.decode(decrypt(data, '12345678ABCDEFGH'));
assert.strictEqual('hello world', result);

PHP

不太懂 PHP 怎么发包,留了一份 gist 了

PHP 的整形类型有点奇怪,因此内部都是用 string 类型来表示。属于“能用”的状态。

使用方法:

<?php

require_once 'tc_tea.php';

$d1 = \TC_TEA\ecb_decrypt("\x56\x27\x6b\xa9\x80\xb9\xec\x16", "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x00");
var_dump(bin2hex($d1));
assert($d1 === "\x01\x02\x03\x04\x05\x06\x07\x08");

mt_srand();
for ($i = 0; $i < 1000; $i++) {
    $v = \TC_TEA\decrypt(\TC_TEA\encrypt("wowowowow", "12345678ABCDEFGH"), "12345678ABCDEFGH");
    assert($v === "wowowowow");
}

$decrypted = \TC_TEA\decrypt(hex2bin("86ebcc7fa8a354f03fa7575e160b2d09c2238ccc13345a9d"), "12345678ABCDEFGH");

var_dump($decrypted);