OpenSSL和Qt打架了?ssf2fcitx改进版 带24个搜狗热皮
〔 下 载 〕
ssf2fcitx在转换部分.ssf文件(如【SUNDAY】黑色炫酷)时,openssl的库里出错:
Program received signal SIGSEGV, Segmentation fault. #0 0x00007ffff7ad2543 in AES_cbc_encrypt () from /lib/x86_64-linux-gnu/libcrypto.so.3 AES_cbc_encrypt(ssfbin + 8, out, static_cast<size_t>(size - 8), &key, iv, AES_DECRYPT);
王小川超过王小云啦?搜狗会造让OpenSSL崩溃的数据啦?What a black day.
它fread文件到char*,解密,调用Qt解压,写入QByteArray. 在libcrypto里出错时,后面那些事都还没干呢。
改成了不用Qt(调用zlib),能成功解密解压。
不过, 黑色炫酷解压后共14个文件,有1个.png,看图软件EOM说CRC Error.
ssf2dir把name.ssf文件解密、解压到name目录中。do-all-ssf.sh批量干这个。
原来的ssf2fcitx被改成了只处理目录,名字改为do-dir,do-all-dir.sh干这个。
每个皮肤一个目录,里面除了图片 (.png)文件,还有.ini配置文件。do-dir把.ini转换为fctix的conf文件。虽然都是INI格式,但key-value等不同。
do-all-dir.sh还把处理完的目录mv到~/.config/fcitx/skin下。
修改配置文件~/.config/fcitx/conf/fcitx-classic-ui.config的最后一行,把SkinType改成<皮肤目录名>。
注销/重启/关机时,fcitx会重写上述配置文件,所以改之前先killall fcitx,改完再fcitx.
比如我这里有两个:
5284 ? 00:00:04 fcitx
5299 ? 00:00:00 fcitx-dbus-watc
pkill fcitx后再启动它,和旧的fcitx-dbus-watc不能配合,输入法就出不来了。
fcitx -d run as daemon(default) 所以不用fcitx&,启动它后按下回车键,就看到shell提示符了。
killall -HUP fcitx 不重新加载配置文件 (完全可以理解,麻烦),输入法没了。
ssf2fcitx要装qtbase5-dev 下载几M,安装几十M,图形部分只是用QImg获取下png文件的大小。
我想把转换部分也去Qt化,get_png_size()写好了 (libpng-dev)。
QSettings用map<string, string>基本写好了,然后发现要转换的行太多了,烦了,把半成品放进包里,收工了。
- 试了一圈后,本人还是用无图版dark
- ssf2fcitx的作者说有些.ssf其实是没加密的.zip
- 解密后iv被修改,再次用它解密结果不对
- openssl/evp.h:const EVP_CIPHER *EVP_aes_256_cbc(void)
- 本例不调用EVP_CIPHER_CTX_cleanup没事
- 函数参数设计成void*和const void*,用户就不必reinterpret_cast<const unsigned char*>buf了。应把麻烦留给自己
- 有人说加密和解密是一样的,本例把Decrypt换成Encrypt,结果不一样
- mkdir时别忘了0755(八进制)而不是755(十进制)
匿名变量作用域演示:
struct MyClass { ~MyClass () { puts("~MyClass"); } void print () const { puts("xxx"); } }; void fn (const MyClass& m) { m.print(); } int main () { fn(MyClass()); puts("---"); } xxx ~MyClass ---
ssf2dir旧源码(包里的有mkdir等):
#include <stdio.h> #include <string.h> #include <locale.h> #include <openssl/aes.h> #include <openssl/evp.h> #include <zlib.h> int AES256_decrypt(void* out_, const void* in_, int n, const void* key, void* iv) { const int BS = AES_BLOCK_SIZE * 1024; //const int BS = n; EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); auto cipher = EVP_aes_256_cbc(); if (!EVP_DecryptInit_ex(ctx, cipher, NULL, (const uint8_t*)key, (uint8_t*)iv)) return 0; uint8_t* out = (uint8_t*)out_; const uint8_t* in = (const uint8_t*)in_; int total = 0, len; while (n > 0) { int m = n > BS ? BS : n; EVP_DecryptUpdate(ctx, out, &len, in, m); if (len != m) printf("update: %d %d %d\n", total, len, m); out += len; total += len; in += m; n -= m; } EVP_DecryptFinal_ex(ctx, out + total, &len); printf("final: %d\n", len); EVP_CIPHER_CTX_cleanup(ctx); EVP_CIPHER_CTX_free(ctx); return total + len; } const uint8_t key[] = { 0x52, 0x36, 0x46, 0x1A, 0xD3, 0x85, 0x03, 0x66, 0x90, 0x45, 0x16, 0x28, 0x79, 0x03, 0x36, 0x23, 0xDD, 0xBE, 0x6F, 0x03, 0xFF, 0x04, 0xE3, 0xCA, 0xD5, 0x7F, 0xFC, 0xA3, 0x50, 0xE4, 0x9E, 0xD9 }; uint8_t iv[] = { 0xE0, 0x7A, 0xAD, 0x35, 0xE0, 0x90, 0xAA, 0x03, 0x8A, 0x51, 0xFD, 0x05, 0xDF, 0x8C, 0x5D, 0x0F }; char x[8 * 1024 * 1024]; int y[2 * 1024 * 1024]; struct QDataStream { uint8_t* p; int pos; QDataStream (void* p_) { p = (uint8_t*)p_; pos = 0; } QDataStream& operator >> (int &n) { n = *((int*)(p + pos)); pos += 4; return *this; } void seek (int pos_) { pos = pos_; } void utf162mbs (char* mbs, int n) { wchar_t wcs[256]; wcs[n] = 0; for (int i = 0; i < n; i++) { wcs[i] = *((uint16_t*)(p + pos)); pos += 2; } wcstombs(mbs, wcs, n + 1); // 其实全是英文名 } operator uint8_t* () { return p + pos; } }; int main (int argc, char* argv[]) { setlocale(LC_ALL, ""); // FILE* fp = fopen("SUNDAY黑色炫酷.ssf", "rb"); FILE* fp = fopen("一二.ssf", "rb"); if (!fp) return 1; fseek(fp, 0, SEEK_END); int size = ftell(fp); rewind(fp); fread(x, 1, size, fp); fclose(fp); int n = AES256_decrypt(y, x + 8, size - 8, key, iv); printf("%d decryped\n", n); size = *y; *y = __builtin_bswap32(size); uLongf _ = size; uncompress((uint8_t*)x, &_, (const uint8_t*)y + 4, n - 4); printf("%d uncompressed\n", size); QDataStream ds(x); ds >> size >> n; n /= 4; printf("%d files\n", n); int ofs[256]; for (int i = 0; i < n; i++) ds >> ofs[i]; for (int i = 0; i < n; i++) { ds.seek(ofs[i]); int len; ds >> len; char name[256], path[256]; ds.utf162mbs(name, len / 2); ds >> len; printf(" %s %d\n", name, len); sprintf(path, "out/%s", name); if (FILE* fp = fopen(path, "w")) fwrite(ds, 1, len, fp), fclose(fp); } }

浙公网安备 33010602011771号