Crypt-Sodium-XS

 view release on metacpan or  search on metacpan

inc/aead.xs  view on Meta::CPAN

=for documentation

libsodium aead provides only algorithm-specific functions.

=cut

MODULE = Crypt::Sodium::XS PACKAGE = Crypt::Sodium::XS::aead

void
_define_constants()
  PREINIT:
  HV *stash = gv_stashpv("Crypt::Sodium::XS::aead", 0);

  PPCODE:
  newCONSTSUB(stash, "aead_chacha20poly1305_ABYTES",
              newSVuv(crypto_aead_chacha20poly1305_ABYTES));
  newCONSTSUB(stash, "aead_chacha20poly1305_ietf_ABYTES",
              newSVuv(crypto_aead_chacha20poly1305_ietf_ABYTES));
  newCONSTSUB(stash, "aead_aes256gcm_ABYTES",
              newSVuv(crypto_aead_aes256gcm_ABYTES));
  newCONSTSUB(stash, "aead_xchacha20poly1305_ietf_ABYTES",
              newSVuv(crypto_aead_xchacha20poly1305_ietf_ABYTES));
  newCONSTSUB(stash, "aead_chacha20poly1305_KEYBYTES",
              newSVuv(crypto_aead_chacha20poly1305_KEYBYTES));
  newCONSTSUB(stash, "aead_chacha20poly1305_ietf_KEYBYTES",
              newSVuv(crypto_aead_chacha20poly1305_ietf_KEYBYTES));
  newCONSTSUB(stash, "aead_aes256gcm_KEYBYTES",
              newSVuv(crypto_aead_aes256gcm_KEYBYTES));
  newCONSTSUB(stash, "aead_xchacha20poly1305_ietf_KEYBYTES",
              newSVuv(crypto_aead_xchacha20poly1305_ietf_KEYBYTES));
  newCONSTSUB(stash, "aead_chacha20poly1305_MESSAGEBYTES_MAX",
              newSVuv(crypto_aead_chacha20poly1305_KEYBYTES));
  newCONSTSUB(stash, "aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX",
              newSVuv(crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX));
  newCONSTSUB(stash, "aead_aes256gcm_MESSAGEBYTES_MAX",
              newSVuv(crypto_aead_aes256gcm_MESSAGEBYTES_MAX));
  newCONSTSUB(stash, "aead_xchacha20poly1305_ietf_MESSAGEBYTES_MAX",
              newSVuv(crypto_aead_xchacha20poly1305_ietf_MESSAGEBYTES_MAX));
  newCONSTSUB(stash, "aead_chacha20poly1305_NPUBBYTES",
              newSVuv(crypto_aead_chacha20poly1305_NPUBBYTES));
  newCONSTSUB(stash, "aead_chacha20poly1305_ietf_NPUBBYTES",
              newSVuv(crypto_aead_chacha20poly1305_ietf_NPUBBYTES));
  newCONSTSUB(stash, "aead_aes256gcm_NPUBBYTES",
              newSVuv(crypto_aead_aes256gcm_NPUBBYTES));
  newCONSTSUB(stash, "aead_xchacha20poly1305_ietf_NPUBBYTES",
              newSVuv(crypto_aead_xchacha20poly1305_ietf_NPUBBYTES));
#ifdef SODIUM_HAS_AEGIS
  newCONSTSUB(stash, "aead_aegis128l_ABYTES",
              newSVuv(crypto_aead_aegis128l_ABYTES));
  newCONSTSUB(stash, "aead_aegis256_ABYTES",
              newSVuv(crypto_aead_aegis256_ABYTES));
  newCONSTSUB(stash, "aead_aegis128l_KEYBYTES",
              newSVuv(crypto_aead_aegis128l_KEYBYTES));
  newCONSTSUB(stash, "aead_aegis256_KEYBYTES",
              newSVuv(crypto_aead_aegis256_KEYBYTES));
  newCONSTSUB(stash, "aead_aegis128l_MESSAGEBYTES_MAX",
              newSVuv(crypto_aead_aegis128l_MESSAGEBYTES_MAX));
  newCONSTSUB(stash, "aead_aegis256_MESSAGEBYTES_MAX",
              newSVuv(crypto_aead_aegis256_MESSAGEBYTES_MAX));
  newCONSTSUB(stash, "aead_aegis128l_NPUBBYTES",
              newSVuv(crypto_aead_aegis128l_NPUBBYTES));
  newCONSTSUB(stash, "aead_aegis256_NPUBBYTES",
              newSVuv(crypto_aead_aegis256_NPUBBYTES));
#endif
=for notes
nsec is not used by libsodium aead algorithms. provided for completeness.
=cut
  newCONSTSUB(stash, "aead_chacha20poly1305_NSECBYTES", newSVuv(0));
  newCONSTSUB(stash, "aead_chacha20poly1305_ietf_NSECBYTES", newSVuv(0));
  newCONSTSUB(stash, "aead_aes256gcm_NSECBYTES", newSVuv(0));
#ifdef SODIUM_HAS_AEGIS
  newCONSTSUB(stash, "aead_aegis128l_NSECBYTES", newSVuv(0));
  newCONSTSUB(stash, "aead_aegis256_NSECBYTES", newSVuv(0));
#endif

inc/aead.xs  view on Meta::CPAN

    croak("aead_decrypt_detached: Failed to grant key protmem RO");
  }

  ret = func(msg_pm->pm_ptr, NULL, ct_buf, ct_len, mac_buf,
             adata_buf, adata_len, nonce_buf, key_buf);

  if (key_pm && protmem_release(aTHX_ key_pm, PROTMEM_FLAG_MPROTECT_RO) != 0) {
    protmem_free(aTHX_ msg_pm);
    croak("aead_decrypt_detached: Failed to release key protmem RO");
  }

  if (protmem_release(aTHX_ msg_pm, PROTMEM_FLAG_MPROTECT_RW) != 0) {
    protmem_free(aTHX_ msg_pm);
    croak("aead_decrypt_detached: Failed to release msg protmem RW");
  }

  if (ret == 0)
    RETVAL = protmem_to_sv(aTHX_ msg_pm, MEMVAULT_CLASS);
  else {
    protmem_free(aTHX_ msg_pm);
    croak("aead_decrypt_detached: Message forged");
  }

  OUTPUT:
  RETVAL

void aead_chacha20poly1305_encrypt( \
  SV * msg, \
  SV * nonce, \
  SV * key, \
  SV * adata = &PL_sv_undef \
)

  ALIAS:
  aead_chacha20poly1305_encrypt_detached = 1
  aead_chacha20poly1305_ietf_encrypt = 2
  aead_chacha20poly1305_ietf_encrypt_detached = 3
  aead_aes256gcm_encrypt = 4
  aead_aes256gcm_encrypt_detached = 5
  aead_xchacha20poly1305_ietf_encrypt = 6
  aead_xchacha20poly1305_ietf_encrypt_detached = 7
  aead_aegis128l_encrypt = 8
  aead_aegis128l_encrypt_detached = 9
  aead_aegis256_encrypt = 10
  aead_aegis256_encrypt_detached = 11

  PREINIT:
  protmem *msg_pm = NULL, *key_pm = NULL;
  SV *ct, *adata_out = NULL;
  unsigned char *msg_buf, *adata_buf = NULL, *nonce_buf, *key_buf, *ct_buf, *adata_out_buf;
  STRLEN msg_len, adata_len = 0, nonce_len, key_len;
  STRLEN adata_req_len, nonce_req_len, key_req_len, out_len;
  int (*comb_func)(unsigned char *, unsigned long long *, const unsigned char *,
                   unsigned long long, const unsigned char *, unsigned long long,
                   const unsigned char *, const unsigned char *, const unsigned char *);
  int (*detached_func)(unsigned char *, unsigned char *, unsigned long long *,
                       const unsigned char *, unsigned long long, const unsigned char *,
                       unsigned long long, const unsigned char *, const unsigned char *,
                       const unsigned char *);

  PPCODE:
  switch(ix) {
    case 2: /* fallthrough */
    case 3:
      adata_req_len = crypto_aead_chacha20poly1305_ietf_ABYTES;
      nonce_req_len = crypto_aead_chacha20poly1305_ietf_NPUBBYTES;
      key_req_len = crypto_aead_chacha20poly1305_ietf_KEYBYTES;
      comb_func = crypto_aead_chacha20poly1305_ietf_encrypt;
      detached_func = crypto_aead_chacha20poly1305_ietf_encrypt_detached;
      break;
    case 4: /* fallthrough */
    case 5:
      if (!has_aes256gcm)
        croak("aead_encrypt: AES256GCM is not supported by this CPU");
      adata_req_len = crypto_aead_aes256gcm_ABYTES;
      nonce_req_len = crypto_aead_aes256gcm_NPUBBYTES;
      key_req_len = crypto_aead_aes256gcm_KEYBYTES;
      comb_func = crypto_aead_aes256gcm_encrypt;
      detached_func = crypto_aead_aes256gcm_encrypt_detached;
      break;
    case 6: /* fallthrough */
    case 7:
      adata_req_len = crypto_aead_xchacha20poly1305_ietf_ABYTES;
      nonce_req_len = crypto_aead_xchacha20poly1305_ietf_NPUBBYTES;
      key_req_len = crypto_aead_xchacha20poly1305_ietf_KEYBYTES;
      comb_func = crypto_aead_xchacha20poly1305_ietf_encrypt;
      detached_func = crypto_aead_xchacha20poly1305_ietf_encrypt_detached;
      break;
    case 8: /* fallthrough */
    case 9:
#ifndef SODIUM_HAS_AEGIS
      croak("aead_encrypt: AEGIS not supported by this version of libsodium");
#else
      adata_req_len = crypto_aead_aegis128l_ABYTES;
      nonce_req_len = crypto_aead_aegis128l_NPUBBYTES;
      key_req_len = crypto_aead_aegis128l_KEYBYTES;
      comb_func = crypto_aead_aegis128l_encrypt;
      detached_func = crypto_aead_aegis128l_encrypt_detached;
#endif
      break;
    case 10: /* fallthrough */
    case 11:
#ifndef SODIUM_HAS_AEGIS
      croak("aead_encrypt: AEGIS not supported by this version of libsodium");
#else
      adata_req_len = crypto_aead_aegis256_ABYTES;
      nonce_req_len = crypto_aead_aegis256_NPUBBYTES;
      key_req_len = crypto_aead_aegis256_KEYBYTES;
      comb_func = crypto_aead_aegis256_encrypt;
      detached_func = crypto_aead_aegis256_encrypt_detached;
#endif
      break;
    case 1: /* fallthrough */
    default:
      adata_req_len = crypto_aead_chacha20poly1305_ABYTES;
      nonce_req_len = crypto_aead_chacha20poly1305_NPUBBYTES;
      key_req_len = crypto_aead_chacha20poly1305_KEYBYTES;
      comb_func = crypto_aead_chacha20poly1305_encrypt;
      detached_func = crypto_aead_chacha20poly1305_encrypt_detached;
  }

inc/aead.xs  view on Meta::CPAN

      RETVAL = sv_keygen(aTHX_ crypto_aead_aegis256_KEYBYTES, flags);
#endif
      break;
    default:
      RETVAL = sv_keygen(aTHX_ crypto_aead_chacha20poly1305_KEYBYTES, flags);
  }

  OUTPUT:
  RETVAL

SV * aead_chacha20poly1305_nonce(SV * base = &PL_sv_undef)

  ALIAS:
  aead_chacha20poly1305_ietf_nonce = 1
  aead_aes256gcm_nonce = 2
  aead_xchacha20poly1305_ietf_nonce = 3
  aead_aegis128l_nonce = 4
  aead_aegis256_nonce = 5

  CODE:
  switch(ix) {
    case 1:
      RETVAL = nonce_generate(aTHX_ crypto_aead_chacha20poly1305_ietf_NPUBBYTES, base);
      break;
    case 2:
      if (!has_aes256gcm)
        croak("aead_nonce: AES256GCM is not supported by this CPU");
      RETVAL = nonce_generate(aTHX_ crypto_aead_aes256gcm_NPUBBYTES, base);
      break;
    case 3:
      RETVAL = nonce_generate(aTHX_ crypto_aead_xchacha20poly1305_ietf_NPUBBYTES, base);
      break;
    case 4:
#ifndef SODIUM_HAS_AEGIS
      croak("aead_nonce: AEGIS not supported by this version of libsodium");
#else
      RETVAL = nonce_generate(aTHX_ crypto_aead_aegis128l_NPUBBYTES, base);
#endif
      break;
    case 5:
#ifndef SODIUM_HAS_AEGIS
      croak("aead_nonce: AEGIS not supported by this version of libsodium");
#else
      RETVAL = nonce_generate(aTHX_ crypto_aead_aegis256_NPUBBYTES, base);
#endif
      break;
    default:
      RETVAL = nonce_generate(aTHX_ crypto_aead_chacha20poly1305_NPUBBYTES, base);
  }

  OUTPUT:
  RETVAL

MODULE = Crypt::Sodium::XS PACKAGE = Crypt::Sodium::XS::aead::precalc

void DESTROY(SV * self)

  PREINIT:
  protmem *precalc_pm;

  PPCODE:
  precalc_pm = protmem_get(aTHX_ self, "Crypt::Sodium::XS::aead::precalc");
  protmem_free(aTHX_ precalc_pm);

SV * decrypt( \
  SV * self, \
  SV * ciphertext, \
  SV * nonce, \
  SV * adata = &PL_sv_undef, \
  SV * flags = &PL_sv_undef \
)

  PREINIT:
  protmem *precalc_pm, *msg_pm;
  unsigned char *ct_buf, *adata_buf = NULL, *nonce_buf;
  STRLEN ct_len, adata_len = 0, nonce_len;
  unsigned int msg_flags = g_protmem_default_flags_decrypt;
  int ret;

  CODE:
  if (!has_aes256gcm)
    croak("decrypt: AES256GCM is not supported by this CPU");

  ct_buf = (unsigned char *)SvPVbyte(ciphertext, ct_len);
  if (ct_len < crypto_aead_aes256gcm_ABYTES)
    croak("decrypt: Invalid ciphertext length (too short)");

  nonce_buf = (unsigned char *)SvPVbyte(nonce, nonce_len);
  if (nonce_len != crypto_aead_aes256gcm_NPUBBYTES)
    croak("decrypt: Invalid nonce length %lu", nonce_len);

  SvGETMAGIC(adata);
  if (SvOK(adata))
    adata_buf = (unsigned char *)SvPVbyte_nomg(adata, adata_len);

  SvGETMAGIC(flags);
  if (SvOK(flags))
    msg_flags = SvUV_nomg(flags);

  msg_pm = protmem_init(aTHX_ ct_len - crypto_aead_aes256gcm_ABYTES, msg_flags);
  if (msg_pm == NULL)
    croak("decrypt: Failed to allocate protmem");

  precalc_pm = protmem_get(aTHX_ self, "Crypt::Sodium::XS::aead::precalc");
  if (protmem_grant(aTHX_ precalc_pm, PROTMEM_FLAG_MPROTECT_RO) != 0) {
    protmem_free(aTHX_ msg_pm);
    croak("decrypt: Failed to grant protmem RO");
  }

  ret = crypto_aead_aes256gcm_decrypt_afternm(msg_pm->pm_ptr, NULL, NULL,
        ct_buf, ct_len, adata_buf, adata_len, nonce_buf,
        (crypto_aead_aes256gcm_state *)precalc_pm->pm_ptr);

  if (protmem_release(aTHX_ precalc_pm, PROTMEM_FLAG_MPROTECT_RO) != 0) {
    protmem_free(aTHX_ msg_pm);
    croak("decrypt: Failed to release procmem RO");
  }

  if (protmem_release(aTHX_ msg_pm, PROTMEM_FLAG_MPROTECT_RW) != 0) {
    protmem_free(aTHX_ msg_pm);
    croak("decrypt: Failed to release msg protmem RW");

inc/aead.xs  view on Meta::CPAN

    croak("decrypt_detached: Invalid mac length %lu", mac_len);

  nonce_buf = (unsigned char *)SvPVbyte(nonce, nonce_len);
  if (nonce_len != crypto_aead_aes256gcm_NPUBBYTES)
    croak("decrypt_detached: Invalid nonce length %lu", nonce_len);

  SvGETMAGIC(adata);
  if (SvOK(adata))
    adata_buf = (unsigned char *)SvPVbyte_nomg(adata, adata_len);

  SvGETMAGIC(flags);
  if (SvOK(flags))
    msg_flags = SvUV_nomg(flags);

  msg_pm = protmem_init(aTHX_ ct_len, msg_flags);
  if (msg_pm == NULL)
    croak("decrypt_detached: Failed to allocate protmem");

  precalc_pm = protmem_get(aTHX_ self, "Crypt::Sodium::XS::aead::precalc");
  if (protmem_grant(aTHX_ precalc_pm, PROTMEM_FLAG_MPROTECT_RO) != 0) {
    protmem_free(aTHX_ msg_pm);
    croak("decrypt_detached: Failed to grant protmem RO");
  }

  ret = crypto_aead_aes256gcm_decrypt_detached_afternm(
    msg_pm->pm_ptr, NULL, ct_buf, ct_len, mac_buf, adata_buf, adata_len,
    nonce_buf, (crypto_aead_aes256gcm_state *)precalc_pm->pm_ptr
  );

  if (protmem_release(aTHX_ precalc_pm, PROTMEM_FLAG_MPROTECT_RO) != 0) {
    protmem_free(aTHX_ msg_pm);
    croak("decrypt_detached: Failed to release protmem RO");
  }

  if (protmem_release(aTHX_ msg_pm, PROTMEM_FLAG_MPROTECT_RW) != 0) {
    protmem_free(aTHX_ msg_pm);
    croak("decrypt_detached: Failed to release msg protmem RW");
  }

  if (ret == 0)
    RETVAL = protmem_to_sv(aTHX_ msg_pm, MEMVAULT_CLASS);
  else {
    protmem_free(aTHX_ msg_pm);
    croak("decrypt_detached: Message forged");
  }

  OUTPUT:
  RETVAL

void encrypt(SV * self, SV * msg, SV * nonce, SV * adata = &PL_sv_undef)

  ALIAS:
  encrypt_detached = 1

  PREINIT:
  protmem *precalc_pm, *msg_pm = NULL;
  SV *ct, *adata_out = NULL;
  unsigned char *msg_buf, *adata_buf = NULL, *nonce_buf, *ct_buf, *adata_out_buf;
  STRLEN msg_len, adata_len = 0, nonce_len, out_len;

  PPCODE:
  nonce_buf = (unsigned char *)SvPVbyte(nonce, nonce_len);
  if (nonce_len != crypto_aead_aes256gcm_NPUBBYTES)
    croak("encrypt: Invalid nonce length %lu", nonce_len);

  SvGETMAGIC(adata);
  if (SvOK(adata))
    adata_buf = (unsigned char *)SvPVbyte_nomg(adata, adata_len);

  if (sv_derived_from(msg, MEMVAULT_CLASS)) {
    msg_pm = protmem_get(aTHX_ msg, MEMVAULT_CLASS);
    msg_buf = msg_pm->pm_ptr;
    msg_len = msg_pm->size;
  }
  else
    msg_buf = (unsigned char *)SvPVbyte(msg, msg_len);

  if (msg_pm && protmem_grant(aTHX_ msg_pm, PROTMEM_FLAG_MPROTECT_RO) != 0)
    croak("encrypt: Failed to grant msg protmem RO");

  precalc_pm = protmem_get(aTHX_ self, "Crypt::Sodium::XS::aead::precalc");
  if (protmem_grant(aTHX_ precalc_pm, PROTMEM_FLAG_MPROTECT_RW) != 0) {
    if (msg_pm)
      protmem_release(aTHX_ msg_pm, PROTMEM_FLAG_MPROTECT_RO);
    croak("encrypt: Failed to grant protmem RW");
  }

  if (ix == 1) {
    Newx(ct_buf, msg_len + 1, unsigned char);
    if (ct_buf == NULL) {
      protmem_release(aTHX_ precalc_pm, PROTMEM_FLAG_MPROTECT_RW);
      if (msg_pm)
        protmem_release(aTHX_ msg_pm, PROTMEM_FLAG_MPROTECT_RO);
      croak("encrypt: Failed to allocate memory");
    }
    ct_buf[msg_len] = '\0';

    Newx(adata_out_buf, crypto_aead_aes256gcm_ABYTES + 1, unsigned char);
    if (adata_out_buf == NULL) {
      protmem_release(aTHX_ precalc_pm, PROTMEM_FLAG_MPROTECT_RW);
      if (msg_pm)
        protmem_release(aTHX_ msg_pm, PROTMEM_FLAG_MPROTECT_RO);
      croak("encrypt: Failed to allocate memory");
    }
    adata_out_buf[crypto_aead_aes256gcm_ABYTES] = '\0';

    crypto_aead_aes256gcm_encrypt_detached_afternm(
      ct_buf, adata_out_buf, NULL, msg_buf, msg_len, adata_buf, adata_len,
      NULL, nonce_buf, (crypto_aead_aes256gcm_state *)precalc_pm->pm_ptr
    );

    ct = newSV(0);
    sv_usepvn_flags(ct, (char *)ct_buf, msg_len, SV_HAS_TRAILING_NUL);
    adata_out = newSV(0);
    sv_usepvn_flags(adata_out, (char *)adata_out_buf,
                    crypto_aead_aes256gcm_ABYTES, SV_HAS_TRAILING_NUL);
  }
  else {
    if (SIZE_MAX - crypto_aead_aes256gcm_ABYTES < msg_len)
      croak("Message too large");
    out_len = crypto_aead_aes256gcm_ABYTES + msg_len;



( run in 0.574 second using v1.01-cache-2.11-cpan-71847e10f99 )