Cipherfix Mitigating Ciphertext Side-Channel Attacks in Software Jan Wichelmann Anna Pätschke Luca Wilke and Thomas Eisenbarth University of Lübeck Lübeck Germany

2025-04-29 0 0 640.51KB 19 页 10玖币
侵权投诉
Cipherfix: Mitigating Ciphertext Side-Channel Attacks in Software
Jan Wichelmann
, Anna Pätschke*
, Luca Wilke, and Thomas Eisenbarth
University of Lübeck, Lübeck, Germany
{j.wichelmann, a.paetschke, l.wilke, thomas.eisenbarth}@uni-luebeck.de
Abstract
Trusted execution environments (TEEs) provide an envi-
ronment for running workloads in the cloud without having to
trust cloud service providers, by offering additional hardware-
assisted security guarantees. However, main memory encryp-
tion as a key mechanism to protect against system-level at-
tackers trying to read the TEE’s content and physical, off-chip
attackers, is insufficient. The recent Cipherleaks attacks infer
secret data from TEE-protected implementations by analyzing
ciphertext patterns exhibited due to deterministic memory en-
cryption. The underlying vulnerability, dubbed the ciphertext
side-channel, is neither protected by state-of-the-art counter-
measures like constant-time code nor by hardware fixes.
Thus, in this paper, we present a software-based, drop-in
solution that can harden existing binaries such that they can
be safely executed under TEEs vulnerable to ciphertext side-
channels, without requiring recompilation. We combine taint
tracking with both static and dynamic binary instrumentation
to find sensitive memory locations, and mitigate the leakage
by masking secret data before it gets written to memory. This
way, although the memory encryption remains determinis-
tic, we destroy any secret-dependent patterns in encrypted
memory. We show that our proof-of-concept implementation
protects various constant-time implementations against ci-
phertext side-channels with reasonable overhead.
1 Introduction
The current trend for data processing and provisioning of
infrastructure heads towards cloud computing, with many co-
located clients sharing the same physical hardware instead
of working in isolated self-hosted environments. To protect
different clients from each other, as well as the hypervisor
from the clients, virtual machines (VMs) are used to provide
isolation. However, especially when processing sensitive data,
users may also want isolation from the hypervisor for data
privacy or regulative reasons. This kind of isolation can be
These authors contributed equally to this work.
provided by trusted execution environments (TEEs), which
model the hypervisor as an untrusted party. To achieve this
kind of isolation, TEEs use a combination of additional access
rights and cryptography to prevent the hypervisor, or more
general, any privileged attacker, from reading the content of
the TEE or interfering with its execution state.
Nevertheless, sharing the same hardware leads to traces
in shared resources like caches which in turn provides an at-
tack surface for timing or microarchitectural side-channels [6,
10,28,34,40]. A widely used countermeasure against these
side-channels is constant-time code that is data oblivious, i.e.,
does not access memory or decide for branch targets based
on secrets [1,52]. To support developers, there are various
mostly automated constant-time analysis tools that observe
different properties of software traces for finding microarchi-
tectural or timing leakage that could lead to exploitable side-
channels [1,17,49
52]. As these tools advance the constant-
time properties of code, leakages get smaller and harder to
find, though recent research has shown that even very small
leakages are exploitable, especially when the strong attacker
model of TEEs is considered [5,36,47].
The recent Cipherleaks paper [33] and its follow-up [31]
introduced a new attack vector on code running in TEEs,
dubbed the ciphertext side-channel. The core idea is that
some TEEs use deterministic memory encryption, resulting
in a
one-to-one
mapping between plaintexts and ciphertexts
for a given memory block. As a result, the attacker can cor-
relate changes in the ciphertext to the processed data. For
example, the secret decision bit of a constant-time swap op-
eration can be leaked by observing whether the ciphertext of
the corresponding memory location changes, showing that
state-of-the-art
constant-time code is not secure under this
attacker model. Thus, this attack vector demands for new
analysis methods and countermeasures.
In this work, we introduce an analysis technique to miti-
gate ciphertext side-channel leakages in constant-time code. A
naive approach hardening every memory write access would
result in a very high performance overhead. Thus, our tech-
nique uses secret-tracking to pinpoint critical memory ac-
arXiv:2210.13124v2 [cs.CR] 1 Mar 2023
cesses, that are then safeguarded by randomizing observable
write patterns such that the resulting binary does not leak in-
formation through the ciphertext side-channel. By combining
static and dynamic approaches, we design a solution that cov-
ers all program components and works without recompilation.
1.1 Our Contribution
We present the CIPHERFIX framework, the first general-
purpose drop-in mitigation for ciphertext side-channel-based
leakages. This includes the following contributions:
We propose an analysis technique based on dynamic taint
analysis to find all secret-containing memory locations in
constant-time binaries that are potentially vulnerable to
the ciphertext side-channel.
We employ dynamic binary analysis to locate stack vari-
ables and enable context-aware tracking of heap alloca-
tions, in order to support robust static instrumentation.
We develop a mitigation technique, based on static binary
instrumentation, that hardens the software binary across
library boundaries without requiring recompilation and
that provides three different security levels.
We evaluate our proof-of-concept implementation of CI-
PHERFIX regarding performance and security on various
primitives from four widely-used cryptographic libraries
and discuss the effects of different mitigation approaches.
Our source code is available at
https://github.com/
UzL-ITS/Cipherfix.
Outline.
After providing background in Section 2, we give
an overview over the design of CIPHERFIX in Section 3. In
Section 4, we present our dynamic analysis, which we use
to build the static mitigation as described in Section 5. We
evaluate the performance and security of our mitigation in
Section 6. Finally, in Section 7, we discuss design decisions
of CIPHERFIX and point out angles for future work.
2 Background
2.1 Secure Encrypted Virtualization
AMD Secure Encrypted Virtualization (SEV) is a trusted
execution environment (TEE) that is designed as a drop-in
solution to protect whole virtual machines. It encrypts the
RAM content of the VM with an encryption key inacces-
sible to the hypervisor [26]. The latest iteration, SEV Se-
cure Nested Paging (SEV-SNP) [2], prevents the hypervisor
from remapping or modifying VM memory, thwarting attacks
like [12,20,32,37,53]. For the memory encryption, SEV uses
AES-128 in the XOR-Encrypt-XOR (XEX) [45] mode of
operation, where a tweak value is XOR-ed before and after
encryption. SEV derives the tweak values from the physi-
cal address of a 16-byte memory block and a random seed
generated at boot time.
2.2 Ciphertext Side-Channel
The ciphertext side-channel was first introduced in [33] and
later generalized to arbitrary memory regions and implemen-
tations in [31]. Both papers extract cryptographic keys from
state-of-the-art constant-time cryptographic implementations
running in SEV-SNP VMs. While the attack vector in [33]
has been fixed on a firmware level [3], the attacks from [31]
remain unaddressed. The core idea is exploiting the deter-
ministic encryption at a fixed memory location, to leak infor-
mation by precisely observing changes in the ciphertext and
correlating them with the (known) executed code.
The authors of [31] introduce two attack variants: The col-
lision and the dictionary attack. Both attacks exploit repeated
write operations to the same memory address. The collision
attack extracts information from observing the same cipher-
text over multiple writes. One common example is the
cswap
pattern (Figure 1): A variable is always written, but depending
on a secret decision bit the old or the new value is selected.
While in the former case the deterministic ciphertext remains
unchanged, in the latter case a new value is written, producing
a different ciphertext. Thus, by observing the ciphertext of
the memory location before and after the
cswap
, the attacker
can immediately infer the secret decision bit. In the dictionary
attack, the attacker does not only rely on collisions, but maps
ciphertexts to (partially) known plaintexts. As the dictionary
attack relies on repeating ciphertexts as well, mitigating the
collision attack also mitigates the dictionary attack.
While the attacks above target values explicitly written to
memory by the application, they can also be used to extract
register values. For this, the authors of [31] exploit that the
operating system running in the SEV-protected VM stores the
user space register values upon context switches on the stack.
This mechanism allows an attacker to extract secrets residing
in registers by forcing context switches and observing the
ciphertexts. However, the authors also describe how to fix this
issue, by randomizing the stack layout.
2.3 Binary Instrumentation
Binary instrumentation allows modifying compiled programs
without access to the source code. This is commonly used to
insert new code that gathers information.
Dynamic binary instrumentation
(DBI) gives the oppor-
tunity to include the architectural state by executing the anal-
ysis routines while the program is running. There are nu-
merous DBI frameworks, e.g., Valgrind [39], Intel Pin [35],
DynamoRIO [9] or DynInst [11]. The Intel Pin framework
compiles and inserts analysis instructions at runtime through
an x86 just-in-time (JIT) compiler. The code is processed
cswap(p, q, b):
c = ~(b - 1); // b = 0 -> c = 00...00
t = c & (p ^ q);
p ^= t;
q ^= t;
(a) Constant-time swap of pand q, depending on bit b.
Ciphertext of p
bbefore cswap after cswap
0e4c80f2a e4c80f2a
1e4c80f2a aa2f2a61
(b) Ciphertext of p, before and after calling cswap.
Figure 1:
cswap
and resulting ciphertexts for the encrypted
RAM accessible by the attacker. 1a shows the procedure of
a constant-time swap. Depending on the value of a secret
decision bit
b
, the values
p
and
q
are swapped (
b=1
), or left
as-is (
b=0
). 1b shows the effect on the resulting ciphertext:
If the ciphertext did not change, the attacker can infer that
b=0
; if the ciphertext changed, the attacker learns that
b=1
.
in units called basic blocks, which are defined as instruction
sequences that have a single entry and exit point. Through a
number of callbacks, a so-called Pintool specifies the analy-
sis code to be inserted during JIT compilation. The original
instructions and the analysis code are combined such that the
instrumentation is transparent to the analyzed program.
Static binary instrumentation
(SBI) results in a modi-
fied standalone binary that is obtained by the use of rewriting
or redirecting techniques. The execution of an instrumented
binary does not depend on an instrumentation framework,
which means that the main overhead comes from the inserted
analysis code [4]. However, static instrumentation struggles
with analyzing indirect branches, shared libraries and dynam-
ically generated code [29,35]. There are different approaches
for adding analysis code to the binary at specific instrumen-
tation points and then redirecting the control flow, such that
both analysis and original application code are executed in the
right order. To avoid breaking references, the instrumented
code can be put into a separate
.instrument
section. An
instrumentation point then redirects execution to this section,
either through software breakpoints via the
int3
[38] instruc-
tion and a custom signal handler, or through direct jumps via
so-called trampolines [11,23,24]. It is possible to combine
multiple approaches to minimize their shortcomings, e.g., by
inserting 5-byte jumps where possible, and falling back to
2-byte jumps or
int3
when not enough space is available. An
example of trampoline-based instrumentation is illustrated in
Figure 8in the appendix. Recent binary rewriting approaches
further optimize the instrumentation through using available
metadata for lifting [54] or symbolization of references [19].
2.4 Dynamic Taint Analysis
Dynamic taint analysis (DTA) tracks the flow of selected in-
formation through a program during code execution. The data
to be tracked is marked as a taint source, and its propagation
is defined through a taint policy. The policy also determines
the taint sinks that can be reached by the data. All instructions
that process secret data are considered for the taint propaga-
tion. Data flow tracking can be done in various granularities,
whereby byte-level tracking is the most commonly used. For
each memory location and register, there is shadow memory
containing the taint label information, so the performance
overhead is directly connected to the granularity. If too much
data is marked as tainted, this is called overtainting; tainting
too little data is referred to as undertainting [4,27,46].
A widely-used x86 taint analysis tool providing fast taint
propagation based on Intel Pin is libdft [27]. In order to
also support 64-bit binaries, libdft has been extended for
VUzzer64 [44] and the AngoraFuzzer [14]. The data flow-
based byte-level taint propagation in libdft64 is implemented
through handwritten rules for every instruction class.
3 CIPHERFIX Design
We first give an overview of the generic design of our cipher-
text side-channel countermeasure.
3.1 Attacker Model
We assume an attacker that tries to extract secret information
from a TEE, that is protected with a deterministic block-based
memory encryption with address-dependent tweaks. The at-
tacker knows the exact binary which is executed by the victim,
but cannot access secret data that is stored within the TEE.
They have root access to the machine running the TEE and
are able to read the entire encrypted memory, but cannot de-
crypt or modify it. Furthermore, the attacker can make use of
a controlled channel that allows them to track and interrupt
the code running inside the victim’s TEE. This means that
they can reconstruct the entire control flow of the targeted ap-
plication and annotate it with snapshots of the corresponding
ciphertexts in memory. One instance of such a scenario is a
malicious hypervisor attacking a VM that is protected with
AMD SEV-SNP. Finally, we assume that potential operat-
ing systems running alongside the targeted application inside
the TEE do properly protect register values from ciphertext
side-channels attacks, as discussed in Section 2.2.
3.2 Countermeasure Requirements
Our overall goal is to produce a hardened binary which does
not contain leaking memory writes. The countermeasure
should not only protect the targeted program itself, but all its
dependencies as well, as leakage may span multiple libraries
(e.g., a crypto library calls
memcpy
in libc), and library de-
velopers are unlikely to widely adopt ciphertext side-channel
countermeasures themselves. Finally, we target application
developers who build code on top of third-party libraries and
who do not have the necessary insight to manually fix leak-
ages in those libraries. Thus, a drop-in solution with little
manual interaction is desirable here.
There are two major approaches to this: One could either
create a compiler extension that rewrites vulnerable memory
accesses at compile time, or modify existing binaries through
SBI. A pure compiler-based solution needs to recompile all
dependencies, which is complex and requires manual inter-
vention. A combination of DBI and SBI can work directly
with the compiled binaries and, given sufficient coverage, ac-
curately identify and harden vulnerable memory writes. For
these reasons, CIPHERFIX aims for a binary instrumentation-
based solution. The trade-off between binary vs. source-based
approaches is further discussed in Section 7.1.
3.3 Protecting Memory Writes
In order to protect an existing binary from being attacked
through a ciphertext side-channel, the content-based patterns
of write accesses to memory have to be obscured. In [31],
the authors propose various approaches for randomizing ob-
served ciphertexts: First, by limiting reuse of memory loca-
tions through using a new address for each memory write;
second, by interleaving data with random nonces; and third,
by applying a random mask when writing data. The first
approach uses the fact that different memory addresses get
different tweak values in the memory encryption, but has a
high overhead when applied outside of well-defined condi-
tions. The second approach requires extensive changes to data
structures, which has many pitfalls and needs to be done by
the compiler. Due to lower overhead and higher practicability,
we thus opt for the last approach, i.e., we add a random mask
whenever an instruction writes secret data to main memory.
We further discuss the different approaches in Section 7.3.
The masking of data takes place before memory writes
and after memory reads. To store the masks belonging to a
particular memory chunk (e.g., a C
++
object), we allocate a
mask buffer of the same size, so there is a one-to-one mapping
of data bytes to mask bytes. When writing data, we generate
and store a new mask, XOR it with the plaintext, and store the
masked plaintext; when reading, we read the mask and then
decode the masked plaintext. Note that we need to ensure that
at no point non-encoded secret data is written to memory, so
all decoding must be done in secure locations like registers.
3.4 Tracking Data Secrecy at Runtime
While masking all memory writes provides good protection,
it comes with a high overhead. In fact, only a fraction of all
memory writes relate to secret information: As we assume
11 22 33 44 59 f1 c0 49
public secret
data
00
mask
secrecy ff00 00 00 ff ff00 ff
00 1c 6d 48 d3 f3 0d
plaintext 4411 22 33 11 2244 33
(a) CIPHERFIX-BASE
11 22 33 44 59 f1 c0 49
public secret
data
00
mask 00 00 00 48 d3 f3 0d
plaintext 4411 22 33 11 2244 33
(b) CIPHERFIX-FAST
Figure 2: CIPHERFIX-BASE stores the secrecy information in
a separate buffer, and uses it to decide whether a given mask
byte should be applied or not. This allows to safely have non-
zero mask bytes behind public data, as they are ignored if the
corresponding secrecy bytes are zero. In contrast, CIPHERFIX-
FAST stores this information directly in the mask buffer, i.e.,
a mask byte is zero iff the corresponding data is public.
that the implementation is constant-time, there is no secret-
dependent control flow, so, for example, return addresses
pushed onto the stack by function calls can be safely written
in clear text. The same is true for the data structures used by
the heap memory allocator to keep track of memory chunks.
Finally, there may be a point where data is no longer consid-
ered secret, e.g., when sending a signature over the network.
We thus aim to find and protect those instructions that actually
deal with secret data. However, this is non-trivial, as there
may be instructions that access both public and secret data,
depending on the context (e.g., from memcpy).
Thus, we need a way to detect at runtime whether a given
memory address should be considered secret, i.e., whether the
data at that address is masked, and whether we should apply a
new mask when writing to said address. We propose two ap-
proaches for storing this secrecy information (Figure 2): In the
first approach, which we denote CIPHERFIX-BASE, we allo-
cate another buffer of the same size as the mask buffer, called
the secrecy buffer. In the second approach, CIPHERFIX-FAST,
we encode this information directly into the mask buffer.
3.4.1 Storing secrecy information separately
In CIPHERFIX-BASE we allocate a buffer that holds the se-
crecy information for each memory location. If a byte is pub-
lic, the corresponding secrecy byte is
0x00
; if a byte is secret,
the secrecy byte is
0xff
. The secrecy buffer is initialized
on allocation, and may be updated during the lifetime of the
object. This construction allows us to read and update data
without branching, as we can combine the secrecy value
S
with the mask
M
via a bitwise AND (
), before applying it to
the data via a bitwise XOR (
): When reading, we compute
P=ˆ
P(MS)
, so we only decode the stored (potentially
masked) plaintext
ˆ
P
if the address is considered secret. For
writing, we always generate and store a new mask, and then
compute
ˆ
P=P(MS)
for plaintext
P
. As we make no
assumptions about the mask, this generally functions as a
摘要:

Cipherx:MitigatingCiphertextSide-ChannelAttacksinSoftwareJanWichelmann,AnnaPätschke*,LucaWilke,andThomasEisenbarthUniversityofLübeck,Lübeck,Germany{j.wichelmann,a.paetschke,l.wilke,thomas.eisenbarth}@uni-luebeck.deAbstractTrustedexecutionenvironments(TEEs)provideanenvi-ronmentforrunningworkloadsin...

展开>> 收起<<
Cipherfix Mitigating Ciphertext Side-Channel Attacks in Software Jan Wichelmann Anna Pätschke Luca Wilke and Thomas Eisenbarth University of Lübeck Lübeck Germany.pdf

共19页,预览4页

还剩页未读, 继续阅读

声明:本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。玖贝云文库仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知玖贝云文库,我们立即给予删除!
分类:图书资源 价格:10玖币 属性:19 页 大小:640.51KB 格式:PDF 时间:2025-04-29

开通VIP享超值会员特权

  • 多端同步记录
  • 高速下载文档
  • 免费文档工具
  • 分享文档赚钱
  • 每日登录抽奖
  • 优质衍生服务
/ 19
客服
关注