Apache Thrift 中的对称加密 (AES)

2024-03-11

我有两个使用 Thrift 进行交互的应用程序。他们共享相同的密钥,我需要加密他们的消息。使用对称算法(例如 AES)是有意义的,但我还没有找到任何库来执行此操作。所以我做了一个研究并看到了以下选项:

使用内置 SSL 支持

我可以使用内置的 SSL 支持,建立安全连接并使用我的密钥作为身份验证令牌。除了已有的密钥之外,它还需要安装证书,但除了检查从客户端接收到的密钥是否与本地存储的密钥相同之外,我不需要执行任何操作。

实施对称加密

到目前为止,有以下几种选择:

  1. Extend TSocket并覆盖write() and read()方法并加密/解密其中的数据。小写入流量将会增加。例如,如果TBinaryProtocol写入 4 字节整数,加密状态下将占用 1 个块(16 字节)。
  2. Extend TSocket并包裹InputStream and OutputStream with CipherInputStream and CipherOutputStream. CipherOutputStream不会立即加密小字节数组,更新Cipher跟他们。当我们有足够的数据后,它们将被加密并写入底层OutputStream。所以它会等到你添加 4 个 4 字节整数并加密它们。它允许我们不浪费流量,但也是问题的一个原因 - 如果最后一个值不能填充块,它将永远不会被加密并写入底层流。它希望我写入可被其块大小(16 字节)整除的字节数,但我不能使用TBinaryProtocol.
  3. 重新实施TBinaryProtocol,缓存所有写入,而不是将它们写入流并加密writeMessageEnd()方法。实现解密readMessageBegin()。我认为加密应该在传输层而不是协议层进行。

请与我分享您的想法。

UPDATE

TFramedTransport 之上的 Java 实现

TEncryptedFramedTransport.java

package tutorial;

import org.apache.thrift.TByteArrayOutputStream;
import org.apache.thrift.transport.TMemoryInputTransport;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TTransportException;
import org.apache.thrift.transport.TTransportFactory;

import javax.crypto.Cipher;
import java.security.Key;
/**
 * TEncryptedFramedTransport is a buffered TTransport. It encrypts fully read message
 * with the "AES/ECB/PKCS5Padding" symmetric algorithm and send it, preceeding with a 4-byte frame size.
 */
public class TEncryptedFramedTransport extends TTransport {
    public static final String ALGORITHM = "AES/ECB/PKCS5Padding";

    private Cipher encryptingCipher;
    private Cipher decryptingCipher;

    protected static final int DEFAULT_MAX_LENGTH = 0x7FFFFFFF;

    private int maxLength_;

    private TTransport transport_ = null;

    private final TByteArrayOutputStream writeBuffer_ = new TByteArrayOutputStream(1024);
    private TMemoryInputTransport readBuffer_ = new TMemoryInputTransport(new byte[0]);

    public static class Factory extends TTransportFactory {
        private int maxLength_;
        private Key secretKey_;

        public Factory(Key secretKey) {
            this(secretKey, DEFAULT_MAX_LENGTH);
        }

        public Factory(Key secretKey, int maxLength) {
            maxLength_ = maxLength;
            secretKey_ = secretKey;
        }

        @Override
        public TTransport getTransport(TTransport base) {
            return new TEncryptedFramedTransport(base, secretKey_, maxLength_);
        }
    }

    /**
     * Constructor wraps around another tranpsort
     */
    public TEncryptedFramedTransport(TTransport transport, Key secretKey, int maxLength) {
        transport_ = transport;
        maxLength_ = maxLength;

        try {
            encryptingCipher = Cipher.getInstance(ALGORITHM);
            encryptingCipher.init(Cipher.ENCRYPT_MODE, secretKey);

            decryptingCipher = Cipher.getInstance(ALGORITHM);
            decryptingCipher.init(Cipher.DECRYPT_MODE, secretKey);
        } catch (Exception e) {
            throw new RuntimeException("Unable to initialize ciphers.");
        }
    }

    public TEncryptedFramedTransport(TTransport transport, Key secretKey) {
        this(transport, secretKey, DEFAULT_MAX_LENGTH);
    }

    public void open() throws TTransportException {
        transport_.open();
    }

    public boolean isOpen() {
        return transport_.isOpen();
    }

    public void close() {
        transport_.close();
    }

    public int read(byte[] buf, int off, int len) throws TTransportException {
        if (readBuffer_ != null) {
            int got = readBuffer_.read(buf, off, len);
            if (got > 0) {
                return got;
            }
        }

        // Read another frame of data
        readFrame();

        return readBuffer_.read(buf, off, len);
    }

    @Override
    public byte[] getBuffer() {
        return readBuffer_.getBuffer();
    }

    @Override
    public int getBufferPosition() {
        return readBuffer_.getBufferPosition();
    }

    @Override
    public int getBytesRemainingInBuffer() {
        return readBuffer_.getBytesRemainingInBuffer();
    }

    @Override
    public void consumeBuffer(int len) {
        readBuffer_.consumeBuffer(len);
    }

    private final byte[] i32buf = new byte[4];

    private void readFrame() throws TTransportException {
        transport_.readAll(i32buf, 0, 4);
        int size = decodeFrameSize(i32buf);

        if (size < 0) {
            throw new TTransportException("Read a negative frame size (" + size + ")!");
        }

        if (size > maxLength_) {
            throw new TTransportException("Frame size (" + size + ") larger than max length (" + maxLength_ + ")!");
        }

        byte[] buff = new byte[size];
        transport_.readAll(buff, 0, size);

        try {
            buff = decryptingCipher.doFinal(buff);
        } catch (Exception e) {
            throw new TTransportException(0, e);
        }

        readBuffer_.reset(buff);
    }

    public void write(byte[] buf, int off, int len) throws TTransportException {
        writeBuffer_.write(buf, off, len);
    }

    @Override
    public void flush() throws TTransportException {
        byte[] buf = writeBuffer_.get();
        int len = writeBuffer_.len();
        writeBuffer_.reset();

        try {
            buf = encryptingCipher.doFinal(buf, 0, len);
        } catch (Exception e) {
            throw new TTransportException(0, e);
        }

        encodeFrameSize(buf.length, i32buf);
        transport_.write(i32buf, 0, 4);
        transport_.write(buf);
        transport_.flush();
    }

    public static void encodeFrameSize(final int frameSize, final byte[] buf) {
        buf[0] = (byte) (0xff & (frameSize >> 24));
        buf[1] = (byte) (0xff & (frameSize >> 16));
        buf[2] = (byte) (0xff & (frameSize >> 8));
        buf[3] = (byte) (0xff & (frameSize));
    }

    public static int decodeFrameSize(final byte[] buf) {
        return
                ((buf[0] & 0xff) << 24) |
                        ((buf[1] & 0xff) << 16) |
                        ((buf[2] & 0xff) << 8) |
                        ((buf[3] & 0xff));
    }
}

乘法服务器.java

package tutorial;

import co.runit.prototype.CryptoTool;
import org.apache.thrift.server.TNonblockingServer;
import org.apache.thrift.server.TServer;
import org.apache.thrift.transport.TNonblockingServerSocket;
import org.apache.thrift.transport.TNonblockingServerTransport;

import java.security.Key;

public class MultiplicationServer {
    public static MultiplicationHandler handler;

    public static MultiplicationService.Processor processor;

    public static void main(String[] args) {
        try {
            handler = new MultiplicationHandler();
            processor = new MultiplicationService.Processor(handler);

            Runnable simple = () -> startServer(processor);

            new Thread(simple).start();
        } catch (Exception x) {
            x.printStackTrace();
        }
    }

    public static void startServer(MultiplicationService.Processor processor) {
        try {
            Key key = CryptoTool.decodeKeyBase64("1OUXS3MczVFp3SdfX41U0A==");

            TNonblockingServerTransport serverTransport = new TNonblockingServerSocket(9090);
            TServer server = new TNonblockingServer(new TNonblockingServer.Args(serverTransport)
                    .transportFactory(new TEncryptedFramedTransport.Factory(key))
                    .processor(processor));

            System.out.println("Starting the simple server...");
            server.serve();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

乘法客户端.java

package tutorial;

import co.runit.prototype.CryptoTool;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;

import java.security.Key;

public class MultiplicationClient {
    public static void main(String[] args) {
        Key key = CryptoTool.decodeKeyBase64("1OUXS3MczVFp3SdfX41U0A==");

        try {
            TSocket baseTransport = new TSocket("localhost", 9090);
            TTransport transport = new TEncryptedFramedTransport(baseTransport, key);
            transport.open();

            TProtocol protocol = new TBinaryProtocol(transport);
            MultiplicationService.Client client = new MultiplicationService.Client(protocol);

            perform(client);

            transport.close();
        } catch (TException x) {
            x.printStackTrace();
        }
    }

    private static void perform(MultiplicationService.Client client) throws TException {
        int product = client.multiply(3, 5);
        System.out.println("3*5=" + product);
    }
}

当然,客户端和服务器上的密钥必须相同。生成并存储为 Base64:

public static String generateKey() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
    KeyGenerator generator = KeyGenerator.getInstance("AES");
    generator.init(128);
    Key key = generator.generateKey();
    return encodeKeyBase64(key);
}

public static String encodeKeyBase64(Key key) {
    return Base64.getEncoder().encodeToString(key.getEncoded());
}

public static Key decodeKeyBase64(String encodedKey) {
    byte[] keyBytes = Base64.getDecoder().decode(encodedKey);
    return new SecretKeySpec(keyBytes, ALGORITHM);
}

UPDATE 2

TFramedTransport 之上的 Python 实现

TEncryptedTransport.py

from cStringIO import StringIO
from struct import pack, unpack
from Crypto.Cipher import AES

from thrift.transport.TTransport import TTransportBase, CReadableTransport

__author__ = 'Marboni'

BLOCK_SIZE = 16

pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * chr(BLOCK_SIZE - len(s) % BLOCK_SIZE)
unpad = lambda s: '' if not s else s[0:-ord(s[-1])]

class TEncryptedFramedTransportFactory:
    def __init__(self, key):
        self.__key = key

    def getTransport(self, trans):
        return TEncryptedFramedTransport(trans, self.__key)


class TEncryptedFramedTransport(TTransportBase, CReadableTransport):
    def __init__(self, trans, key):
        self.__trans = trans
        self.__rbuf = StringIO()
        self.__wbuf = StringIO()

        self.__cipher = AES.new(key)

    def isOpen(self):
        return self.__trans.isOpen()

    def open(self):
        return self.__trans.open()

    def close(self):
        return self.__trans.close()

    def read(self, sz):
        ret = self.__rbuf.read(sz)
        if len(ret) != 0:
            return ret

        self.readFrame()
        return self.__rbuf.read(sz)

    def readFrame(self):
        buff = self.__trans.readAll(4)
        sz, = unpack('!i', buff)
        encrypted = StringIO(self.__trans.readAll(sz)).getvalue()

        decrypted = unpad(self.__cipher.decrypt(encrypted))

        self.__rbuf = StringIO(decrypted)

    def write(self, buf):
        self.__wbuf.write(buf)

    def flush(self):
        wout = self.__wbuf.getvalue()
        self.__wbuf = StringIO()

        encrypted = self.__cipher.encrypt(pad(wout))
        encrypted_len = len(encrypted)
        buf = pack("!i", encrypted_len) + encrypted
        self.__trans.write(buf)
        self.__trans.flush()

    # Implement the CReadableTransport interface.
    @property
    def cstringio_buf(self):
        return self.__rbuf

    def cstringio_refill(self, prefix, reqlen):
        while len(prefix) < reqlen:
            self.readFrame()
            prefix += self.__rbuf.getvalue()
        self.__rbuf = StringIO(prefix)
        return self.__rbuf

乘法客户端.py

import base64
from thrift import Thrift
from thrift.transport import TSocket
from thrift.protocol import TBinaryProtocol

from tutorial import MultiplicationService, TEncryptedTransport

key = base64.b64decode("1OUXS3MczVFp3SdfX41U0A==")

try:
    transport = TSocket.TSocket('localhost', 9090)
    transport = TEncryptedTransport.TEncryptedFramedTransport(transport, key)

    protocol = TBinaryProtocol.TBinaryProtocol(transport)
    client = MultiplicationService.Client(protocol)

    transport.open()

    product = client.multiply(4, 5, 'Echo!')
    print '4*5=%d' % product

    transport.close()
except Thrift.TException, tx:
    print tx.message

正如 JensG 所说,发送外部加密的二进制文件或提供分层密码传输是两个最佳选择。如果您需要模板,请查看 TFramedTransport。它是一种简单的分层传输,可以轻松用作创建 TCipherTransport 的起始块。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Apache Thrift 中的对称加密 (AES) 的相关文章

  • Abaqus 将曲面转化为集合

    我一直试图在模型中找到两个表面的中心 参见照片 但未能成功 它们是元素表面 面 查询中没有选项可以查找元素表面的中心 只能查找元素集的中心 找到节点集的中心也很好 但是我的节点集没有出现在工具 gt 查询 gt 质量属性选项中 而且我找不到
  • 以编程方式在java的resources/source文件夹中创建文件?

    我有两个资源文件夹 src 这是我的 java 文件 资源 这是我的资源文件 图像 properties 组织在文件夹 包 中 有没有办法以编程方式在该资源文件夹中添加另一个 properties 文件 我尝试过这样的事情 public s
  • Geopandas 设置几何图形:MultiPolygon“等于 len 键和值”的 ValueError

    我有 2 个带有几何列的地理数据框 我将一些几何图形从 1 个复制到另一个 这对于多边形效果很好 但对于任何 有效 多多边形都会返回 ValueError 请指教如何解决这个问题 我不知道是否 如何 为什么应该更改 MultiPolygon
  • HTTPS 代理不适用于 Python 的 requests 模块

    我对 Python 还很陌生 我一直在使用他们的 requests 模块作为 PHP 的 cURL 库的替代品 我的代码如下 import requests import json import os import urllib impor
  • 如何在selenium服务器上提供自定义功能?

    我知道可以通过某种方法获得一些硒功能 其中之一如下 driver getCapabilities getBrowserName 它返回浏览器名称的值 但如果它指的是一个可用的方法 如果我没有误解的话 这似乎与自定义功能有关 就像我的意思是
  • Javafx过滤表视图

    我正在尝试使用文本字段来过滤表视图 我想要一个文本字段 txtSearch 来搜索 nhs 号码 名字 姓氏 和 分类类别 我尝试过在线实施各种解决方案 但没有运气 我对这一切仍然很陌生 所以如果问得不好 我深表歉意 任何帮助将不胜感激 我
  • 欧洲中部时间 14 日 3 月 30 日星期五 00:00:00 至 日/月/年

    我尝试解析格式日期Fri Mar 30 00 00 00 CET 14至 日 月 年 这是我的代码 SimpleDateFormat formatter new SimpleDateFormat dd MM yyyy System out
  • 循环中断打破tqdm

    下面的简单代码使用tqdm https github com tqdm tqdm在循环迭代时显示进度条 import tqdm for f in tqdm tqdm range 100000000 if f gt 100000000 4 b
  • Jersey 客户端请求中未设置 Content-Length-Header

    我正在使用 Jersey Client 访问网络服务 如下所示 response r accept MediaType TEXT PLAIN TYPE header content length 0 post String class 其中
  • Numpy 优化

    我有一个根据条件分配值的函数 我的数据集大小通常在 30 50k 范围内 我不确定这是否是使用 numpy 的正确方法 但是当数字超过 5k 时 它会变得非常慢 有没有更好的方法让它更快 import numpy as np N 5000
  • Struts 2 + Sitemesh 3 集成 - FreemarkerDecoratorServlet 中的 NPE

    我将 Struts 2 版本 2 3 14 3 与 Sitemesh 3 版本 3 0 alpha 2 一起使用 并且在某些情况下遇到 NullPointerException 首先 这是我的 web xml 中的 struts2 site
  • 如何在JSTL中调​​用java方法? [复制]

    这个问题在这里已经有答案了 这可能是重复的问题 我只想调用不是 getter 或 setter 方法的方法例如 xyz 类的 makeCall someObj stringvalue Java类 Class XYZ public Strin
  • 我可以创建自定义 java.* 包吗?

    我可以创建一个与预定义包同名的自己的包吗在Java中 比如java lang 如果是这样 结果会怎样 这难道不能让我访问该包的受保护的成员 如果不是 是什么阻止我这样做 No java lang被禁止 安全管理器不允许 自定义 类java
  • 替换后增量

    我自己已经有一个问题了 但我想扩展它后增量示例 https stackoverflow com questions 51308967 post increment with example char a D int b 5 System o
  • 如何从没有结尾的管道中读取 python 中的 stdin

    当管道来自 打开 时 不知道正确的名称 我无法从 python 中的标准输入或管道读取数据 文件 我有作为例子管道测试 py import sys import time k 0 try for line in sys stdin k k
  • 为什么这个作业不起作用?

    我有课Results which extends ArrayList
  • FileOutputStream.close() 中的设备 ioctl 不合适

    我有一些代码可以使用以下命令将一些首选项保存到文件中FileOutputStream 这是我已经写了一千遍的标准代码 FileOutputStream out new FileOutputStream file try BufferedOu
  • 改变字典的哈希函数

    按照此question https stackoverflow com questions 37100390 towards understanding dictionaries 我们知道两个不同的字典 dict 1 and dict 2例
  • 带有 Maven Wrapper 的 Java 17 导致无法识别的 VM 选项“MaxPermSize=512m”

    I use OpenJDK 17 https jdk java net 17 使用 Maven Wrapper 3 8 2 从春季初始化 https start spring io Maven项目 JAR打包 Java 17 Spring
  • Pandas 与 Numpy 数据帧

    看这几行代码 df2 df copy df2 1 df 1 df 1 values 1 df2 ix 0 0 我们的教练说我们需要使用 values属性来访问底层的 numpy 数组 否则我们的代码将无法工作 我知道 pandas Data

随机推荐

  • 填充其父项的 ListBoxItem

    我正在开发一个 Windows Phone 应用程序 我有以下 XAML
  • 将相对路径转换为绝对路径?

    我不确定这些路径是否重复 给定相对路径 如何使用 shell 脚本确定绝对路径 Example relative path x y a b z c d absolute path a b c d 我在unix中遇到的最可靠的方法是readl
  • 为什么不能在 Slick 中使用已编译的 Insert 语句

    狡猾的专家 我正在学习和使用 Slick 我有一个问题 文档说编译查询仅适用于选择 更新和删除 http slick typesafe com doc 2 0 0 queries html compiled queries http sli
  • Spark DataFrame 重新分区:未保留的分区数

    根据 Spark 1 6 3 的文档 repartition partitionExprs Column 应保留结果数据框中的分区数量 返回按给定分区划分的新 DataFrame 保留现有分区数量的表达式 取自https spark apa
  • 无法启动模拟器:错误:模拟器在 60 秒内未连接

    我无法使用 VSCode for Flutter 进行调试 我正在使用 Windows 并且正在尝试使用 Android 模拟器 我尝试重新安装 Flutter Android SDK 和 VSCode 来解决该问题 并尝试设置环境变量 这
  • 恢复 C# Windows 窗体背景色

    我在 Windows 窗体窗体上有一个按钮 我将其背景颜色更改为Color Yellow当它被点击时 当再次单击它时 我想将其恢复为原始默认外观 默认背景色是SystemColor Control 当第一次单击按钮时 我唯一改变的是 btn
  • iOS 的标准语法解析器是什么?

    iPad 和 iPhone 的 iOS 支持解析器吗 特别是 lex yacc 或 flex bison 是否可用于 iOS 开发 xcode4 有原生支持的库吗 我可以通过 lex yacc 生成语法 然后获取 c 文件并将它们放入我的项
  • 在当前正在写入的文件上创建 FileInfo 是否安全?

    在我的应用程序 C 4 5 winforms 应用程序 中 我定期检查文件夹的内容并将找到的任何文件的详细信息存储到数据库中 在此例程中 我创建了一个FileInfo实例使用new FileInfo path 我读了属性CreationTi
  • 使用 Apache POI 读取 excel 文件

    我创建了这段代码来使用 Apache POI 读取 excel 文件的内容 我使用 eclipse 作为编辑器 但是当我运行代码时 我在粗体行中遇到了问题 有什么问题 excel的内容如下 Emp ID Name Salary 1 0 jo
  • Jenkins 与 Google Cloud 源存储库

    我正在尝试使用 Jenkins 进行 CI CD 我开发了一个Python Flask 应用程序 我正在将此应用程序部署到 Google App Engine 中 到目前为止我正在使用gcloud app deploy app yaml将应
  • 单击提交时验证文本区域

    我正在开发允许用户向系统发送反馈的网站 我使用文本区域和提交按钮创建了反馈表 最重要的是 当用户点击提交时 如果用户输入了一些我不希望他们输入的单词 该反馈将不会发送到系统 它会提醒用户在点击提交之前删除该单词 从现在开始 我只是创建一个简
  • 数据库中的最佳货币格式

    在我的数据库中与 ASP NET Web 应用程序结合使用的最佳货币格式是什么 我不确定浮点数和小数哪个更好 请注意 我不需要特定于文化的设置 如果您使用的是 SQL Server 则您拥有 money 类型 它会转换为 NET 中的十进制
  • 条件成员函数

    关于在 C 类中条件定义成员函数的建议是什么 问题集中在限制 DLL 中某些类的外部暴露 特别是当这些类作为参数传入时 显然这不是您想要对数据成员做的事情 但是函数应该没问题 不是吗 例如 class A public void func1
  • django 中的自定义 404 和 500 页面 -> DEBUG = True

    我想向客户展示我的网站示例 它还没有完全完成 但是对我来说隐藏错误并且不显示我的代码库非常重要 如果在开发模式下发生服务器错误 django 会执行哪些操作 就像这样 Django 描述出了什么问题 https i stack imgur
  • D3.js 中的日期格式

    我在 csv 中有一个列 日期 它将日期存储在 2003 02 01 年月日 中 我想将日期格式化为月份和年份 例如 2003 年 4 月 我该怎么做 var format d3 time format m Y data forEach f
  • 除了网站之外,还有 Webpack splitchunks.name 作为功能文档吗?

    随着 webpack 4 的引入 splitChunks name用于定义分割块的名称 在这里 文档说可以将键映射到自定义命名的函数 https webpack js org plugins split chunks plugin spli
  • C# 接口实现 - 为什么这不能构建?

    抱歉 如果之前有人问过这个问题 但实际上不可能用谷歌搜索 我认为 int 数组实现了 IEnumerable 因此 Thing 应该能够实现 IThing 怎么没有呢 public interface IThing IEnumerable
  • 普遍的 SQL 查询

    是否有人有一个查询来搜索 Pervasive 数据库中所有表中的所有列以获取特定值 我正在努力寻找有关此的任何信息 在 sql server 中似乎很容易做到 但在 Pervasive 中则不然 返回按表名排序的所有表的列表 按 xf na
  • IntelliJ IDEA 中的 JSP 调试

    有谁知道如何调试JSP in IntelliJ IDEA 当我在我的中设置断点时JSP文件中 这些断点似乎从未生效 调试器永远不会碰到它们 IDEA 似乎认为断点是有效的 我确实看到一个红点放置在我放置断点的行的左侧 我在 IntelliJ
  • Apache Thrift 中的对称加密 (AES)

    我有两个使用 Thrift 进行交互的应用程序 他们共享相同的密钥 我需要加密他们的消息 使用对称算法 例如 AES 是有意义的 但我还没有找到任何库来执行此操作 所以我做了一个研究并看到了以下选项 使用内置 SSL 支持 我可以使用内置的