Skip to content

Commit

Permalink
patch 9.0.1682: sodium encryption is not portable
Browse files Browse the repository at this point in the history
Problem: crypt: sodium encryption is not portable
Solution: use little-endian byte order for sodium encrypted files

As mentioned in #12586, sodium encryption only works on little ending
architectures, because reading and writing the sodium encryption
parameters are stored in the encrypted files in an arch-dependent way.

This of course fails for big-endian architectures like s390.

So make sure to use little-endian byte order when reading and writing
sodium encrypted files.

fixes: #12586
closes: 12655
  • Loading branch information
chrisbra committed Aug 9, 2023
1 parent 92f076e commit 6019fed
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 15 deletions.
103 changes: 88 additions & 15 deletions src/crypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ typedef struct {
static int crypt_sodium_init_(cryptstate_T *state, char_u *key, crypt_arg_T *arg);
static long crypt_sodium_buffer_decode(cryptstate_T *state, char_u *from, size_t len, char_u **buf_out, int last);
static long crypt_sodium_buffer_encode(cryptstate_T *state, char_u *from, size_t len, char_u **buf_out, int last);
# if defined(FEAT_SODIUM) || defined(PROTO)
static void crypt_long_long_to_char(long long n, char_u *s);
static void crypt_int_to_char(int n, char_u *s);
static long long crypt_char_to_long_long(char_u *s);
static int crypt_char_to_int(char_u *s);
#endif
#if defined(FEAT_EVAL) && defined(FEAT_SODIUM)
static void crypt_sodium_report_hash_params(unsigned long long opslimit, unsigned long long ops_def, size_t memlimit, size_t mem_def, int alg, int alg_def);
#endif
Expand Down Expand Up @@ -966,35 +972,45 @@ crypt_sodium_init_(
// "cat_add" should not be NULL, check anyway for safety
if (state->method_nr == CRYPT_M_SOD2 && arg->cat_add != NULL)
{
memcpy(arg->cat_add, &opslimit, sizeof(opslimit));
arg->cat_add += sizeof(opslimit);
char_u buffer[20];
char_u *p = buffer;
vim_memset(buffer, 0, 20);

crypt_long_long_to_char(opslimit, p);
p += sizeof(opslimit);

memcpy(arg->cat_add, &memlimit, sizeof(memlimit));
arg->cat_add += sizeof(memlimit);
crypt_long_long_to_char(memlimit, p);
p += sizeof(memlimit);

memcpy(arg->cat_add, &alg, sizeof(alg));
arg->cat_add += sizeof(alg);
crypt_int_to_char(alg, p);
memcpy(arg->cat_add, buffer, sizeof(opslimit) + sizeof(memlimit) + sizeof(alg));
}
}
else
{
char_u buffer[20];
char_u *p = buffer;
vim_memset(buffer, 0, 20);
int size = sizeof(opslimit) +
sizeof(memlimit) + sizeof(alg);

// Reading parameters from file
if (arg->cat_add_len
< (int)(sizeof(opslimit) + sizeof(memlimit) + sizeof(alg)))
if (arg->cat_add_len < size)
{
sodium_free(sd_state);
return FAIL;
}

// derive the key from the file header
memcpy(&opslimit, arg->cat_add, sizeof(opslimit));
arg->cat_add += sizeof(opslimit);

memcpy(&memlimit, arg->cat_add, sizeof(memlimit));
arg->cat_add += sizeof(memlimit);
memcpy(p, arg->cat_add, size);
arg->cat_add += size;

memcpy(&alg, arg->cat_add, sizeof(alg));
arg->cat_add += sizeof(alg);
opslimit = crypt_char_to_long_long(p);
p += sizeof(opslimit);
memlimit = crypt_char_to_long_long(p);
p += sizeof(memlimit);
alg = crypt_char_to_int(p);
p += sizeof(alg);

#ifdef FEAT_EVAL
crypt_sodium_report_hash_params(opslimit,
Expand Down Expand Up @@ -1327,6 +1343,63 @@ crypt_sodium_report_hash_params(
}
}
#endif

static void
crypt_long_long_to_char(long long n, char_u *s)
{
int i;
for (i = 0; i < 8; i++)
{
s[i] = (char_u)(n & 0xff);
n = (unsigned)n >> 8;
}
}

static void
crypt_int_to_char(int n, char_u *s)
{
int i;
for (i = 0; i < 4; i++)
{
s[i] = (char_u)(n & 0xff);
n = (unsigned)n >> 8;
}
}

static long long
crypt_char_to_long_long(char_u *s)
{
unsigned long long retval = 0;
int i;
for (i = 7; i >= 0; i--)
{
if (i == 7)
retval = s[i];
else
retval |= s[i];
if (i > 0)
retval <<= 8;
}
return retval;
}

static int
crypt_char_to_int(char_u *s)
{
int retval = 0;
int i;

for (i = 3; i >= 0; i--)
{
if (i == 3)
retval = s[i];
else
retval |= s[i];
if (i > 0)
retval <<= 8;
}
return retval;
}
# endif

#endif // FEAT_CRYPT
2 changes: 2 additions & 0 deletions src/version.c
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,8 @@ static char *(features[]) =

static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1682,
/**/
1681,
/**/
Expand Down

0 comments on commit 6019fed

Please sign in to comment.