<commit_before>/*
 * crypto.c :  cryptographic routines
 *
 * ====================================================================
 *    Licensed to the Apache Software Foundation (ASF) under one
 *    or more contributor license agreements.  See the NOTICE file
 *    distributed with this work for additional information
 *    regarding copyright ownership.  The ASF licenses this file
 *    to you under the Apache License, Version 2.0 (the
 *    "License"); you may not use this file except in compliance
 *    with the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing,
 *    software distributed under the License is distributed on an
 *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *    KIND, either express or implied.  See the License for the
 *    specific language governing permissions and limitations
 *    under the License.
 * ====================================================================
 */

#include "crypto.h"

#if APU_HAVE_CRYPTO
#include <apr_random.h>
#include <apr_crypto.h>

#include "svn_types.h"

#include "svn_private_config.h"
#include "private/svn_atomic.h"


/* 1000 iterations is the recommended minimum, per RFC 2898, section 4.2.  */
#define NUM_ITERATIONS 1000


/* Set this define if we need stronger randomness.  (Or if that
   decision is permanent, just remove this #define and enable the code
   below which uses it to conditionalize functionality.)  */
#define NEED_RANDOMER_RANDOMNESS 0


/* A structure for containing Subversion's cryptography-related bits
   (so we can avoid passing around APR-isms outside this module). */
struct svn_crypto__ctx_t {
  apr_crypto_t *crypto;  /* APR cryptography context. */

#if NEED_RANDOMER_RANDOMNESS
  /* ### For now, we will use apr_generate_random_bytes(). If we need more
     ### strength, then we can use that function to generate entropy for
     ### seeding apr_random_t. See httpd/server/core.c:ap_init_rng()  */
  apr_random_t *rand;
#endif
};




/*** Initialization ***/


/* One-time initialization of the cryptography subsystem. */
static volatile svn_atomic_t crypto_init_state = 0;


#define CRYPTO_INIT(scratch_pool) \
  SVN_ERR(svn_atomic__init_once(&crypto_init_state, \
                                crypto_init, NULL, (scratch_pool)))


/* Initialize the APR cryptography subsystem (if available), using
   ANY_POOL's ancestor root pool for the registration of cleanups,
   shutdowns, etc.   */
/* Don't call this function directly!  Use svn_atomic__init_once(). */
static svn_error_t *
crypto_init(void *baton, apr_pool_t *any_pool)
{
  /* NOTE: this function will locate the topmost ancestor of ANY_POOL
     for its cleanup handlers. We don't have to worry about ANY_POOL
     being cleared.  */
  apr_status_t apr_err = apr_crypto_init(any_pool);
  if (apr_err)
    return svn_error_wrap_apr(apr_err,
                              _("Failed to initialize cryptography "
                                "subsystem"));

  return SVN_NO_ERROR;
}




/*** Helper Functions ***/


/* If APU_ERR is non-NULL, create and return a Subversion error using
   APR_ERR and APU_ERR. */
static svn_error_t *
err_from_apu_err(apr_status_t apr_err,
                 const apu_err_t *apu_err)
{
  if (apu_err)
    return svn_error_createf(apr_err, NULL,
                             _("code (%d), reason (\"%s\"), msg (\"%s\")"),
                             apu_err->rc,
                             apu_err->reason ? apu_err->reason : "",
                             apu_err->msg ? apu_err->msg : "");
  return SVN_NO_ERROR;
}


/* Generate a Subversion error which describes the state reflected by
   APR_ERR and any crypto errors registered with CTX. */
static svn_error_t *
crypto_error_create(svn_crypto__ctx_t *ctx,
                    apr_status_t apr_err,
                    const char *msg)
{
  const apu_err_t *apu_err;
  apr_status_t rv = apr_crypto_error(&apu_err, ctx->crypto);
  svn_error_t *child;

  /* Ugh. The APIs are a bit slippery, so be wary.  */
  if (apr_err == APR_SUCCESS)
    apr_err = APR_EGENERAL;

  if (rv == APR_SUCCESS)
    child = err_from_apu_err(apr_err, apu_err);
  else
    child = svn_error_wrap_apr(rv, _("Fetching error from APR"));

  return svn_error_create(apr_err, child, msg);
}


/* Set RAND_BYTES to a block of bytes containing random data RAND_LEN
   long and allocated from RESULT_POOL. */
static svn_error_t *
get_random_bytes(const unsigned char **rand_bytes,
                 svn_crypto__ctx_t *ctx,
                 apr_size_t rand_len,
                 apr_pool_t *result_pool)
{
#if APR_HAS_RANDOM
  apr_status_t apr_err;
  unsigned char *bytes;

  bytes = apr_palloc(result_pool, rand_len);
  apr_err = apr_generate_random_bytes(bytes, rand_len);
  if (apr_err != APR_SUCCESS)
    return svn_error_wrap_apr(apr_err, _("Error obtaining random data"));

  *rand_bytes = bytes;
  return SVN_NO_ERROR;
#else
  return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
                          _("No support for random data generation found"));
#endif
}


/* Set CTX to a Subversion cryptography context allocated from
   RESULT_POOL.  */
svn_error_t *
svn_crypto__context_create(svn_crypto__ctx_t **ctx,
                           apr_pool_t *result_pool)
{
  apr_status_t apr_err;
  const apu_err_t *apu_err = NULL;
  const apr_crypto_driver_t *driver;

  CRYPTO_INIT(result_pool);

  *ctx = apr_palloc(result_pool, sizeof(**ctx));

#if NEED_RANDOMER_RANDOMNESS
  /* ### Seeding with entropy is needed. See svn_crypto__ctx_t comments.  */
  ctx->rand = apr_random_standard_new(result_pool);
#endif

  apr_err = apr_crypto_get_driver(&driver, "openssl", NULL, &apu_err,
                                  result_pool);
  /* Potential bugs in get_driver() imply we might get APR_SUCCESS and NULL.
     Sigh. Just be a little more careful in error generation here.  */
  if (apr_err != APR_SUCCESS)
    return svn_error_create(apr_err, err_from_apu_err(apr_err, apu_err),
                            _("OpenSSL crypto driver error"));
  if (driver == NULL)
    return svn_error_create(APR_EGENERAL,
                            err_from_apu_err(APR_EGENERAL, apu_err),
                            _("Bad return value while loading"));

  apr_err = apr_crypto_make(&(*ctx)->crypto, driver, NULL, result_pool);
  if (apr_err != APR_SUCCESS || (*ctx)->crypto == NULL)
    return svn_error_create(apr_err, NULL,
                            _("Error creating OpenSSL crypto context"));

  return SVN_NO_ERROR;
}


/* Return an svn_string_t allocated from RESULT_POOL, with its .data
   and .len members set to DATA and LEN, respective.

   WARNING: No lifetime management of DATA is offered here, so you<commit_msg>* subversion/libsvn_subr/crypto.c   Mostly remove a partially-implemented more-randomer-randomness   implemention, leaving just a single explanatory comment and   structure member pointing us in the right direction should we choose   to travel that road.<commit_after>/*
 * crypto.c :  cryptographic routines
 *
 * ====================================================================
 *    Licensed to the Apache Software Foundation (ASF) under one
 *    or more contributor license agreements.  See the NOTICE file
 *    distributed with this work for additional information
 *    regarding copyright ownership.  The ASF licenses this file
 *    to you under the Apache License, Version 2.0 (the
 *    "License"); you may not use this file except in compliance
 *    with the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing,
 *    software distributed under the License is distributed on an
 *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *    KIND, either express or implied.  See the License for the
 *    specific language governing permissions and limitations
 *    under the License.
 * ====================================================================
 */

#include "crypto.h"

#if APU_HAVE_CRYPTO
#include <apr_random.h>
#include <apr_crypto.h>

#include "svn_types.h"

#include "svn_private_config.h"
#include "private/svn_atomic.h"


/* 1000 iterations is the recommended minimum, per RFC 2898, section 4.2.  */
#define NUM_ITERATIONS 1000


/* A structure for containing Subversion's cryptography-related bits
   (so we can avoid passing around APR-isms outside this module). */
struct svn_crypto__ctx_t {
  apr_crypto_t *crypto;  /* APR cryptography context. */

#if 0
  /* ### For now, we will use apr_generate_random_bytes(). If we need
     ### more strength, then we can set this member using
     ### apr_random_standard_new(), then use
     ### apr_generate_random_bytes() to generate entropy for seeding
     ### apr_random_t. See httpd/server/core.c:ap_init_rng()  */
  apr_random_t *rand;
#endif
};




/*** Initialization ***/


/* One-time initialization of the cryptography subsystem. */
static volatile svn_atomic_t crypto_init_state = 0;


#define CRYPTO_INIT(scratch_pool) \
  SVN_ERR(svn_atomic__init_once(&crypto_init_state, \
                                crypto_init, NULL, (scratch_pool)))


/* Initialize the APR cryptography subsystem (if available), using
   ANY_POOL's ancestor root pool for the registration of cleanups,
   shutdowns, etc.   */
/* Don't call this function directly!  Use svn_atomic__init_once(). */
static svn_error_t *
crypto_init(void *baton, apr_pool_t *any_pool)
{
  /* NOTE: this function will locate the topmost ancestor of ANY_POOL
     for its cleanup handlers. We don't have to worry about ANY_POOL
     being cleared.  */
  apr_status_t apr_err = apr_crypto_init(any_pool);
  if (apr_err)
    return svn_error_wrap_apr(apr_err,
                              _("Failed to initialize cryptography "
                                "subsystem"));

  return SVN_NO_ERROR;
}




/*** Helper Functions ***/


/* If APU_ERR is non-NULL, create and return a Subversion error using
   APR_ERR and APU_ERR. */
static svn_error_t *
err_from_apu_err(apr_status_t apr_err,
                 const apu_err_t *apu_err)
{
  if (apu_err)
    return svn_error_createf(apr_err, NULL,
                             _("code (%d), reason (\"%s\"), msg (\"%s\")"),
                             apu_err->rc,
                             apu_err->reason ? apu_err->reason : "",
                             apu_err->msg ? apu_err->msg : "");
  return SVN_NO_ERROR;
}


/* Generate a Subversion error which describes the state reflected by
   APR_ERR and any crypto errors registered with CTX. */
static svn_error_t *
crypto_error_create(svn_crypto__ctx_t *ctx,
                    apr_status_t apr_err,
                    const char *msg)
{
  const apu_err_t *apu_err;
  apr_status_t rv = apr_crypto_error(&apu_err, ctx->crypto);
  svn_error_t *child;

  /* Ugh. The APIs are a bit slippery, so be wary.  */
  if (apr_err == APR_SUCCESS)
    apr_err = APR_EGENERAL;

  if (rv == APR_SUCCESS)
    child = err_from_apu_err(apr_err, apu_err);
  else
    child = svn_error_wrap_apr(rv, _("Fetching error from APR"));

  return svn_error_create(apr_err, child, msg);
}


/* Set RAND_BYTES to a block of bytes containing random data RAND_LEN
   long and allocated from RESULT_POOL. */
static svn_error_t *
get_random_bytes(const unsigned char **rand_bytes,
                 svn_crypto__ctx_t *ctx,
                 apr_size_t rand_len,
                 apr_pool_t *result_pool)
{
#if APR_HAS_RANDOM
  apr_status_t apr_err;
  unsigned char *bytes;

  bytes = apr_palloc(result_pool, rand_len);
  apr_err = apr_generate_random_bytes(bytes, rand_len);
  if (apr_err != APR_SUCCESS)
    return svn_error_wrap_apr(apr_err, _("Error obtaining random data"));

  *rand_bytes = bytes;
  return SVN_NO_ERROR;
#else
  return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
                          _("No support for random data generation found"));
#endif
}


/* Set CTX to a Subversion cryptography context allocated from
   RESULT_POOL.  */
svn_error_t *
svn_crypto__context_create(svn_crypto__ctx_t **ctx,
                           apr_pool_t *result_pool)
{
  apr_status_t apr_err;
  const apu_err_t *apu_err = NULL;
  const apr_crypto_driver_t *driver;

  CRYPTO_INIT(result_pool);

  *ctx = apr_palloc(result_pool, sizeof(**ctx));

  apr_err = apr_crypto_get_driver(&driver, "openssl", NULL, &apu_err,
                                  result_pool);
  /* Potential bugs in get_driver() imply we might get APR_SUCCESS and NULL.
     Sigh. Just be a little more careful in error generation here.  */
  if (apr_err != APR_SUCCESS)
    return svn_error_create(apr_err, err_from_apu_err(apr_err, apu_err),
                            _("OpenSSL crypto driver error"));
  if (driver == NULL)
    return svn_error_create(APR_EGENERAL,
                            err_from_apu_err(APR_EGENERAL, apu_err),
                            _("Bad return value while loading"));

  apr_err = apr_crypto_make(&(*ctx)->crypto, driver, NULL, result_pool);
  if (apr_err != APR_SUCCESS || (*ctx)->crypto == NULL)
    return svn_error_create(apr_err, NULL,
                            _("Error creating OpenSSL crypto context"));

  return SVN_NO_ERROR;
}


/* Return an svn_string_t allocated from RESULT_POOL, with its .data
   and .len members set to DATA and LEN, respective.

   WARNING: No lifetime management of DATA is offered here, so you
{'fraction_non_alphanumeric': 0.10519297725757464, 'fraction_numerical': 0.002963182457959849, 'mean_word_length': 3.0419161676646707, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 24, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1761643', 'n_tokens_mistral': 4342, 'n_tokens_neox': 4236, 'n_words': 1254}