Commit d19b08d5 authored by YUSHIQIAN's avatar YUSHIQIAN

basic timing attack 2081 experiments

parent 07ee78d2
This diff is collapsed.
This diff is collapsed.
CC = gcc
CFLAGS = -Wall -ansi -c -O3
INCLUDES = -I./include
LD = gcc
LDFLAGS =
LIBS =
SRCS = $(wildcard src/*.c)
OBJS = $(patsubst %.c,%.o,$(SRCS))
EXECS = ta des_ta
BINDIR = /datas/teaching/courses/HWSec/labs/bin
.PHONY: help all clean ultraclean
help:
@echo "Type:"
@echo "<make> or <make help> to get this help message"
@echo "<make all> to generate the 'ta' and 'des_ta' executable"
@echo "<make clean> to clean a bit"
@echo "<make ultraclean> to really clean"
all: $(EXECS)
ta: ta.o p.o $(OBJS)
$(LD) $(LDFLAGS) $^ -o $@ $(LIBS) -lm
des_ta: des_ta.o p.o $(OBJS)
$(LD) $(LDFLAGS) $^ -o $@ $(LIBS) -lm
%.o: %.c
$(CC) $(CFLAGS) $(INCLUDES) $< -o $@
clean:
rm -f $(OBJS) des_ta.o p.o ta.o
ultraclean:
rm -f $(OBJS) $(EXECS) des_ta.o ta.o ta.o
File added
/**********************************************************************************
Copyright Institut Telecom
Contributors: Renaud Pacalet (renaud.pacalet@telecom-paristech.fr)
This software is a computer program whose purpose is to experiment timing and
power attacks against crypto-processors.
This software is governed by the CeCILL license under French law and
abiding by the rules of distribution of free software. You can use,
modify and/ or redistribute the software under the terms of the CeCILL
license as circulated by CEA, CNRS and INRIA at the following URL
"http://www.cecill.info".
As a counterpart to the access to the source code and rights to copy,
modify and redistribute granted by the license, users are provided only
with a limited warranty and the software's author, the holder of the
economic rights, and the successive licensors have only limited
liability.
In this respect, the user's attention is drawn to the risks associated
with loading, using, modifying and/or developing or reproducing the
software by the user in light of its specific status of free software,
that may mean that it is complicated to manipulate, and that also
therefore means that it is reserved for developers and experienced
professionals having in-depth computer knowledge. Users are therefore
encouraged to load and test the software's suitability as regards their
requirements in conditions enabling the security of their systems and/or
data to be ensured and, more generally, to use and operate it in the
same conditions as regards security.
The fact that you are presently reading this means that you have had
knowledge of the CeCILL license and that you accept its terms. For more
information see the LICENCE-fr.txt or LICENSE-en.txt files.
**********************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/times.h>
#include <stdint.h>
#include <inttypes.h>
#include <string.h>
#include <math.h>
#include <utils.h>
#include <des.h>
#include <rdtsc_timer.h>
uint64_t
rand_uint64_t (void)
{
uint64_t res;
int i;
res = UINT64_C (0x0);
for (i = 0; i < 4; i++)
{
res <<= 16;
res |= (uint64_t) (rand () & 0xffff);
}
return res;
}
extern uint64_t des_p_ta (uint64_t val);
uint64_t
des_f_ta (uint64_t rk, uint64_t val)
{
if (val >> 32)
{
ERROR (-1, "illegal R input value for F function: %016" PRIx64, val);
}
if (rk >> 48)
{
ERROR (-1, "illegal RK input value for F function: %016" PRIx64, rk);
}
return des_p_ta (des_sboxes (des_e (val) ^ rk));
}
uint64_t
des_enc_ta (uint64_t * ks, uint64_t val)
{
uint64_t lr, r, l, tmp;
int i;
lr = des_ip (val);
r = des_right_half (lr);
l = des_left_half (lr);
for (i = 0; i < 16; i++)
{
tmp = r;
r = l ^ des_f_ta (ks[i], r);
l = tmp;
}
return des_fp ((r << 32) | l);
}
extern int
des_check_f (uint64_t (*f_enc) (uint64_t *, uint64_t),
uint64_t (*f_dec) (uint64_t *, uint64_t));
int
des_check_ta (void)
{
return des_check_f (des_enc_ta, des_dec);
}
int
measure (uint64_t * ks, uint64_t pt, double th, int average, double *time,
uint64_t * ct)
{
uint64_t a, b, t, min, *m;
int i, n, cnt;
if (average < 1)
{
ERROR (-1, "illegal average value: %d", average);
}
if (th < 1.0)
{
ERROR (-1, "illegal threshold value: %f", th);
}
m = XCALLOC (average, sizeof (uint64_t));
min = UINT64_C (0);
for (i = 0; i < average; i++)
{
a = get_rdtsc_timer ();
*ct = des_enc_ta (ks, pt);
b = get_rdtsc_timer ();
t = b - a;
m[i] = t;
if (i == 0 || t < min)
{
min = t;
}
}
n = 0;
i = 0;
cnt = average;
while (n < average)
{
if (m[i] <= th * min)
{
n += 1;
i = (i + 1) % average;
}
else
{
do
{
a = get_rdtsc_timer ();
*ct = des_enc_ta (ks, pt);
b = get_rdtsc_timer ();
cnt += 1;
t = b - a;
}
while (t > min * th);
if (t < min)
{
n = 0;
min = t;
}
m[i] = t;
n += 1;
i = (i + 1) % average;
}
}
t = 0;
for (i = 0; i < average; i++)
{
t += m[i];
}
*time = (double) (t) / (double) (average);
return cnt;
}
#define TH 1.1
#define AVG 10
uint64_t str2key(char *);
int
main (int argc, char **argv)
{
int n, i, j, k, l;
uint64_t ks[16], pt, ct, key;
double t;
#ifdef SRAND
struct tms dummy;
#endif
if (!des_check_ta ())
{
ERROR (-1, "%s: DES functional test failed", argv[0]);
}
if (argc != 3)
{
ERROR (-1, "usage: %s <n> <key>", argv[0]);
}
n = atoi (argv[1]);
if (n < 1)
{
ERROR (-1,
"%s: number of experiments (<n>) shall be greater than 1 (%d)",
argv[0], n);
}
key = str2key(argv[2]);
des_ks (ks, key);
#ifdef DEBUG
for (i = 0; i < 8; i++)
{
fprintf (stderr, "%02" PRIx32 " ",
(uint32_t) ((ks[15] >> ((7 - i) * 6)) & UINT64_C (0x3f)));
}
fprintf (stderr, "\n");
#endif
#ifdef SRAND
srand (times (&dummy));
#else
srand (0);
#endif
j = n / 100;
k = 0;
l = 0;
for (i = 0; i < n; i++)
{
pt = rand_uint64_t ();
if (i == 0)
{
printf ("%016" PRIx64 "\n", pt);
}
measure (ks, pt, TH, AVG, &t, &ct);
if (ct != des_enc_ta (ks, pt))
{
ERROR (-1, "data dependent DES functionally incorrect");
}
printf ("%016" PRIx64 " %f\n", ct, t);
k += 1;
if (k == j)
{
l += 1;
fprintf (stderr, "%3d%%", l);
k = 0;
}
}
fprintf (stderr, "\n");
return 0;
}
uint64_t str2key(char * str) {
uint64_t res;
int i, v;
v = 0;
res = UINT64_C (0);
for(i = 0; i < strlen(str); i++) {
switch(str[i]) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9': v = str[i] - '0';
break;
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f': v = str[i] - 'a' + 10;
break;
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F': v = str[i] - 'A' + 10;
break;
default: ERROR (-1, "unvalid key value: %s", str);
break;
}
if((res >> 60) != UINT64_C (0)) {
ERROR (-1, "key overflow: %s", str);
}
res = (res << 4) | (uint64_t)(v);
}
return res;
}
File added
/** \file des.h
* The \b des library, a software library dedicated to the Data Encryption
* Standard (DES).
* \author Renaud Pacalet, renaud.pacalet@telecom-paristech.fr
* \date 2009-07-08
* \attention
* <ol>
* <li>Most functions of the \b des library check their input parameters and
* issue warnings or errors when they carry illegal values. Warnings are
* printed on the standard error output. Errors are also printed on the
* standard error output and the program exits with a -1 exit status.</li>
* <li>The \b des library uses a single data type to represent all the data of
* the DES standard: ::uint64_t. It is a 64 bits unsigned integer.</li>
* <li>Data are always right aligned: when the data width is less than 64 bits,
* the meaningful bits are always the rightmost bits of the ::uint64_t.</li>
* </ol>
*/
#ifndef DES_H
#define DES_H
#include <stdint.h>
#include <inttypes.h>
/** Number of left shifts per round.
* left_shifts[0] corresponds to round #1, ... left_shifts[15] corresponds to
* round #16. A value of 0 means one shift. A value of 1 means two shifts. */
extern uint8_t left_shifts[16];
/** Initial permutation (64 to 64 bits).
* Same as des_n_fp(). \return The permutated input as a 64 bits ::uint64_t. */
uint64_t des_ip (uint64_t val /**< 64 bits input. */ );
/** Inverse of initial permutation (64 to 64 bits).
* Same as des_fp(). \return The permutated input as a 64 bits ::uint64_t. */
uint64_t des_n_ip (uint64_t val /**< 64 bits input. */ );
/** Final permutation (64 to 64 bits).
* Inverse of initial permutation, same as des_n_ip(). \return The permutated
* input as a 64 bits ::uint64_t. */
uint64_t des_fp (uint64_t val /**< 64 bits input. */ );
/** Inverse of final permutation (64 to 64 bits).
* Same as des_ip(). \return The permutated input as a 64 bits ::uint64_t. */
uint64_t des_n_fp (uint64_t val /**< 64 bits input. */ );
/** E expansion - permutation (32 to 48 bits). \return The expanded and
* permutated input as a 48 bits ::uint64_t. */
uint64_t des_e (uint64_t val /**< 32 bits input. */ );
/** Inverse of E expansion - permutation (48 to 32 bits).
* Duplicated bits must have the same value. If they do not, an error is raised.
* \return The permutated and selected input as a 32 bits ::uint64_t. */
uint64_t des_n_e (uint64_t val /**< 48 bits input. */ );
/** P permutation (32 to 32 bits). \return The permutated input as a 32 bits
* ::uint64_t. */
uint64_t des_p (uint64_t val /**< 32 bits input. */ );
/** Inverse of P permutation (32 to 32 bits). \return The permutated input as a
* 32 bits ::uint64_t. */
uint64_t des_n_p (uint64_t val /**< 32 bits input. */ );
/** PC1 permutation - selection (64 to 56 bits).
* No parity check. \return The permutated and selected input as a 56 bits
* ::uint64_t. */
uint64_t des_pc1 (uint64_t val /**< 64 bits input. */ );
/** Computes the 8 parity bits of a 64 bits word.
* Parity bits are the rightmost bit of each byte. Once computed, the number of
* set bits of each byte is odd, as specified in the DES standard. \return The
* input with odd parity bits, as a 64 bits ::uint64_t. */
uint64_t des_set_parity_bits (uint64_t val /**< 64 bits input. */ );
/** Inverse of PC1 permutation - selection (56 to 64 bits).
* Parity bits are computed. \return The permutated and expanded input as a 64
* bits ::uint64_t. */
uint64_t des_n_pc1 (uint64_t val /**< 56 bits input. */ );
/** PC2 permutation - selection (56 to 48 bits). \return The permutated and
* selected input as a 48 bits ::uint64_t. */
uint64_t des_pc2 (uint64_t val /**< 56 bits input. */ );
/** Inverse of PC2 permutation - selection (48 to 56 bits).
* Missing bits are set to 0. \return The permutated and expanded input as a 56
* bits ::uint64_t. */
uint64_t des_n_pc2 (uint64_t val /**< 48 bits input. */ );
/** Single SBox computation (6 to 4 bits). \return The 4 bits output of SBox
* number ::sbox corresponding to the 4 bits input, as a 4 bits
* ::uint64_t. */
uint64_t des_sbox (int sbox /**< SBox number, from 1 to 8. */ ,
uint64_t val
/**< 6 bits input. */
);
/** All SBoxes computation (48 to 32 bits). \return The 32 bits output of all
* SBoxes corresponding to the 48 bits input, as a 32 bits ::uint64_t. */
uint64_t des_sboxes (uint64_t val /**< 48 bits input. */ );
/** Returns the 32 bits right half of a 64 bits word. \return The 32 bits right
* half of a 64 bits word, as a 32 bits ::uint64_t. */
uint64_t des_right_half (uint64_t val /**< 64 bits input. */ );
/** Returns the 32 bits left half of a 64 bits word. \return The 32 bits left
* half of a 64 bits word, as a 32 bits ::uint64_t. */
uint64_t des_left_half (uint64_t val /**< 64 bits input. */ );
/** Applies the <strong>left shift</strong> rotation of the standard (56 to 56
* bits). \return The rotated input, as a 56 bits ::uint64_t. */
uint64_t des_ls (uint64_t val /**< 56 bits input. */ );
/** Applies the <strong>right shift</strong> rotation of the standard (56 to 56
* bits). \return The rotated input, as a 56 bits ::uint64_t. */
uint64_t des_rs (uint64_t val /**< 56 bits input. */ );
/** The F function of the standard (48+32 bits to 32 bits). \return The
* transformed input, as a 32 bits ::uint64_t. */
uint64_t des_f (uint64_t rk /**< 48 bits round key. */ ,
uint64_t val
/**< 32 bits data input. */
);
/** Computes the whole key schedule from a 64 bits secret key and stores the
* sixteen 48 bits round keys in an array. \return The sixteen 48 bits round
* keys in the array passed as first parameter. */
void des_ks (
/** The array where to store the sixteen 48 bits round keys.
* On return \e ks[0] holds the first round key, ..., \e ks[15] holds the
* last round key. Must be allocated prior the call. */
uint64_t * ks, uint64_t val
/**< 64 bits key. */
);
/** Enciphers a 64 bits plaintext with a pre-computed key schedule. \return The
* enciphered plaintext as a 64 bits ::uint64_t. */
uint64_t des_enc (uint64_t * ks /**< The pre-computed key schedule. */ ,
uint64_t val
/**< The 64 bits plaintext. */
);
/** Deciphers a 64 bits plaintext with a pre-computed key schedule. \return The
* deciphered ciphertext as a 64 bits ::uint64_t. */
uint64_t des_dec (uint64_t * ks /**< The pre-computed key schedule. */ ,
uint64_t val
/**< The 64 bits ciphertext. */
);
/** A functional verification of the DES implementation. Runs a number of
* encipherments with des_enc() and the corresponding decipherments with
* des_dec() and checks the results against pre-computed plaintext, ciphertexts
* and secret keys. If compiled in DEBUG mode, prints warnings on mismatches or
* a \b OK message if the tests pass. Returns one on success, zero on errors. */
int des_check (void);
#endif /** not DES_H */
This diff is collapsed.
/**********************************************************************************
Copyright Institut Telecom
Contributors: Renaud Pacalet (renaud.pacalet@telecom-paristech.fr)
This software is a computer program whose purpose is to experiment timing and
power attacks against crypto-processors.
This software is governed by the CeCILL license under French law and
abiding by the rules of distribution of free software. You can use,
modify and/ or redistribute the software under the terms of the CeCILL
license as circulated by CEA, CNRS and INRIA at the following URL
"http://www.cecill.info".
As a counterpart to the access to the source code and rights to copy,
modify and redistribute granted by the license, users are provided only
with a limited warranty and the software's author, the holder of the
economic rights, and the successive licensors have only limited
liability.
In this respect, the user's attention is drawn to the risks associated
with loading, using, modifying and/or developing or reproducing the
software by the user in light of its specific status of free software,
that may mean that it is complicated to manipulate, and that also
therefore means that it is reserved for developers and experienced
professionals having in-depth computer knowledge. Users are therefore
encouraged to load and test the software's suitability as regards their
requirements in conditions enabling the security of their systems and/or
data to be ensured and, more generally, to use and operate it in the
same conditions as regards security.
The fact that you are presently reading this means that you have had
knowledge of the CeCILL license and that you accept its terms. For more
information see the LICENCE-fr.txt or LICENSE-en.txt files.
**********************************************************************************/
/** \file pcc.h
* The \b pcc library, a software library dedicated to the computation of
* Pearson Correlation Coefficients (PCC).
* \author Renaud Pacalet, renaud.pacalet@telecom-paristech.fr
* \date 2009-07-08
*
* Defines a data structure and a set of functions used to compute and manage
* Pearson Correlation Coefficients (PCC) between scalar, floating point
* (double) random variables. These coefficients are a statistical tool to
* evaluate the correlation between two random variables. The formula of a PCC
* between random variables X and Y is:<br>
* PCC(X, Y) = [E(X*Y) - E(X)*E(Y)] / [s(X) * s(Y)]<br>
* where E(Z) is the expectation (average value) of random variable Z and s(Z)
* is its unbiased standard deviation. The value of the PCC is in range -1 to
* +1. Values close to 0 indicate no or a weak correlation. Values close to -1
* or +1 indicate strong correlations.<br>
* The \b pcc library can be used to compute a set of PCCs between one random
* variable (denoted X), common to all PCCs, and a set of random variables
* (denoted Y0, Y1, ..., Yn-1). To compute such a set of PCCs one must first
* initialize a PCC context (pcc_init()), indicating the number ny of Y random
* variables. Then, realizations of the random variables must be accumulated
* into the context: first a realization of the X variable (pcc_insert_x()),
* followed by realizations of each of the ny Y variables (pcc_insert_y()). Once
* a sufficient number of realizations are accumulated in the PCC context, a
* call to pcc_consolidate() computes the ny PCCs. Calls to pcc_get_pcc() return
* their values. Note: more realizations can be accumulated after a call to
* pcc_consolidate(), another call to pcc_consolidate() will take them into
* account altogether with the previous ones and compute the new PCC values. A
* call to pcc_free() deallocates the PCC context and makes it reusable for the
* computation of a new set of PCCs. Example of use with ny=4 Y variables, in
* which get_next_x and get_next_y are two functions returning realizations of
* the random variables:
* \code
* pcc_context ctx;
* double x, y, pcc;
* int i, j, nexp;
* ...
* ctx = pcc_init(4); // Initialize context for four Y random variables
* for(i = 0; i < nexp; i++) // For nexp experiments
* {
* x = get_next_x(); // Realization of random variable X
* pcc_insert_x(ctx, x); // Insert realization of X into context
* for(j = 0; j < 4; j++) // For the four Y random variables
* {
* y = get_next_y(j); // Realization of random variable Yj
* pcc_insert_y(ctx, j, y); // Insert realization of Yj into context
* } // End for the four Y random variables
* } // End for nexp experiments
* pcc_consolidate(ctx); // Finalize computation of the four PCCs
* for(j = 0; j < 4; j++) // For the four Y random variables
* {
* pcc = pcc_get_pcc(ctx, j); // Get PCC(X,Yj)
* printf("PCC(X, Y%d) = %lf\n", j, pcc); // Print PCC(X,Yj)
* } // End for the four Y random variables
* pcc_free(ctx); // Deallocate context
* ctx = pcc_init(12); // Initialize context for twelve other Y random variables
* ...
* pcc_free(ctx); // Deallocate context
* \endcode
* \attention
* It is an error to break the realization insertion scheme: if you initialized
* your PCC context for ny Y variables, first insert a realization of X,
* followed by one and only one realization of each of the ny Y variables. Then,
* insert a new realization of X and ny new realizations of the ny Y variables,
* and so on. Consolidate only after inserting the realization of the last Y
* variable. Do not consolidate when in an intermediate state.
* */
#ifndef PCC_H
#define PCC_H
/** The data structure used to compute and manage a set of Pearson correlation
* coefficients. */
struct pcc_context_s
{
int ny; /**< The number of Y random variables. */
int nr; /**< The current number of realizations of the random variables. */
double rx; /**< The last inserted realization of X. */
double x; /**< The sum of the realizations of X. */
double x2; /**< The sum of the squares of the realizations of X. */
double *y; /**< The array of the sums of the realizations of the Ys. */
double *y2; /**< The array of the sums of the squares of the realizations of the Ys. */
double *xy; /**< The array of the sums of the products between realizations of X and Ys. */
double *pcc; /**< The array of the PCCs. */
char state; /**< Tracker for insertion of the realizations. */
int cnt; /**< Tracker for insertion of the realizations. */
char *flags; /**< Tracker for insertion of the realizations. */
};
/** Pointer to the pcc_context_s data structure. */
typedef struct pcc_context_s *pcc_context;
/** Initializes a PCC context.
* \return An initialized PCC context. */
pcc_context pcc_init (int ny
/**< The number of Y random variables to manage. */
);
/** Inserts a new X realization in a PCC context. */
void pcc_insert_x (pcc_context ctx,
/**< The PCC context. */
double x
/**< The realization of the X random variable. */
);
/** Inserts a new Y realization in a PCC context. */
void pcc_insert_y (pcc_context ctx,
/**< The PCC context. */
int ny,
/**< The index of the Y random variable (0 to ctx->ny - 1). */
double y
/**< The realization of the Y random variable. */
);
/** Consolidates a set of PCCs (computes all the PCCs from the already inserted
* realizations). */
void pcc_consolidate (pcc_context ctx
/**< The PCC context. */
);
/** Gets the PCCs from a consolidated PCC context. */
double pcc_get_pcc (pcc_context ctx,
/**< The PCC context. */
int ny
/**< The index of the PCC to get (0 to ctx->ny - 1). */
);
/** Deallocates a PCC context. */
void pcc_free (pcc_context ctx
/**< The PCC context. */
);
#endif /** not PCC_H */
/**********************************************************************************
Copyright Institut Telecom
Contributors: Renaud Pacalet (renaud.pacalet@telecom-paristech.fr)
This software is a computer program whose purpose is to experiment timing and
power attacks against crypto-processors.
This software is governed by the CeCILL license under French law and
abiding by the rules of distribution of free software. You can use,
modify and/ or redistribute the software under the terms of the CeCILL
license as circulated by CEA, CNRS and INRIA at the following URL
"http://www.cecill.info".
As a counterpart to the access to the source code and rights to copy,
modify and redistribute granted by the license, users are provided only
with a limited warranty and the software's author, the holder of the
economic rights, and the successive licensors have only limited
liability.
In this respect, the user's attention is drawn to the risks associated
with loading, using, modifying and/or developing or reproducing the
software by the user in light of its specific status of free software,
that may mean that it is complicated to manipulate, and that also
therefore means that it is reserved for developers and experienced
professionals having in-depth computer knowledge. Users are therefore
encouraged to load and test the software's suitability as regards their
requirements in conditions enabling the security of their systems and/or
data to be ensured and, more generally, to use and operate it in the
same conditions as regards security.
The fact that you are presently reading this means that you have had
knowledge of the CeCILL license and that you accept its terms. For more
information see the LICENCE-fr.txt or LICENSE-en.txt files.
**********************************************************************************/
/** \file rdtsc_timer.h
* A function that returns the current value of the internal timer.
* \author Renaud Pacalet, renaud.pacalet@telecom-paristech.fr
* \date 2009-07-08
* \attention
* Not portable, tested only on Pentium architecture under Linux.
*
* Example of use to time a function 10 times and return the minimum time value
* as a floating point (double): \code
* uint64_t a, b;
* int i;
* double t, min;
* ...
* for(i = 0; i < 10; i++)
* {
* a = get_rdtsc_timer();
* function_to_time();
* b = get_rdtsc_timer();
* t = (double)(b - a);
* if(i == 0 || t < min)
* {
* min = t;
* }
* }
* return min;
* \endcode
*/
#ifndef RDTSC_TIMER_H
#define RDTSC_TIMER_H
#include <stdint.h>
/** A function that returns the current value of the internal timer. \return the
* timer value as a 64 bits unsigned integer. */
uint64_t get_rdtsc_timer (void);
#endif /* not RDTSC_TIMER_H */
/**********************************************************************************
Copyright Institut Telecom
Contributors: Renaud Pacalet (renaud.pacalet@telecom-paristech.fr)
This software is a computer program whose purpose is to experiment timing and
power attacks against crypto-processors.
This software is governed by the CeCILL license under French law and
abiding by the rules of distribution of free software. You can use,
modify and/ or redistribute the software under the terms of the CeCILL
license as circulated by CEA, CNRS and INRIA at the following URL
"http://www.cecill.info".
As a counterpart to the access to the source code and rights to copy,
modify and redistribute granted by the license, users are provided only
with a limited warranty and the software's author, the holder of the
economic rights, and the successive licensors have only limited
liability.
In this respect, the user's attention is drawn to the risks associated
with loading, using, modifying and/or developing or reproducing the
software by the user in light of its specific status of free software,