%% options copyright owner = Dirk Krause copyright year = 2015-xxxx license = bsd %% header /** @file dk4md.h Message digests. This module provides a simple API to use the message digest routines from the OpenSSL library. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/). This product includes cryptographic software written by Eric Young (eay@cryptsoft.com). This product includes software written by Tim Hudson (tjh@cryptsoft.com). */ #include "dk4conf.h" #include "dk4binenc.h" #include "dk4error.h" #if DK4_HAVE_OPENSSL_MD5_H #ifndef OPENSSL_MD5_H_INCLUDED #include #define OPENSSL_MD5_H_INCLUDED 1 #endif #endif #if DK4_HAVE_OPENSSL_SHA_H #ifndef OPENSSL_SHA_H_INCLUDED #include #define OPENSSL_SHA_H_INCLUDED 1 #endif #endif #if DK4_HAVE_OPENSSL_RIPEMD_H #ifndef OPENSSL_RIPEMD_H_INCLUDED #include #define OPENSSL_RIPEMD_H_INCLUDED 1 #endif #endif /* At the moment the largest supported message digest is SHA-512, producing 512 bit (64 bytes) of binary data. */ enum { /** Size of largest binary message digest. */ DK4MD_BUFFER_SIZE_BINARY = 64 }; enum { /** Size of largest text message digest, 2 * DK4MD_BUFFER_SIZE_BINARY + 16. */ DK4MD_BUFFER_SIZE_TEXT = 144 }; /** Message digest creator. */ typedef struct { char obuf[DK4MD_BUFFER_SIZE_TEXT]; /**< Result buffer. */ unsigned char bbuf[16 + DK4MD_BUFFER_SIZE_BINARY]; /**< Binary buffer. */ union { #if DK4_HAVE_SHA384 || DK4_HAVE_SHA512 SHA512_CTX sha512; /**< SHA-512, SHA-384. */ #endif #if DK4_HAVE_SHA224 || DK4_HAVE_SHA256 SHA256_CTX sha256; /**< SHA-256, SHA-224. */ #endif #if DK4_HAVE_OPENSSL_SHA_H SHA_CTX sha; /**< SHA-1. */ #endif #if DK4_HAVE_OPENSSL_RIPEMD_H RIPEMD160_CTX ripemd160; /**< RIPEMD-160. */ #endif #if DK4_HAVE_OPENSSL_MD5_H MD5_CTX md5; /**< MD5. */ #endif int dummy; /**< If none of the above defined. */ } ctx; /**< Message digest context. */ int mdtype; /**< Message digest type. */ int encoding; /**< Required output encoding. */ } dk4_md_ctx_t; #ifdef __cplusplus extern "C" { #endif /** Initialize CTX structure. @param ctxptr Structure to initialize. @param mdt Message digest type, one from: DK4_MD_MD5, DK4_MD_SHA1, DK4_MD_SHA224, DK4_MD_SHA256, DK4_MD_SHA384, DK4_MD_SHA512, or DK4_MD_RIPEMD_160. @param mde Message digest encoding, one from: DK4_BINARY_TO_TEXT_ENCODING_HEX or DK4_BINARY_TO_TEXT_ENCODING_A85. @param erp Error report, may be NULL. @return 1 on success, 0 on error. Error codes: - DK4_E_INVALID_ARGUMENTS
if ctxptr is NULL, - DK4_E_SYNTAX
if an invalid value is specified for mdt or mde, - DK4_E_NOT_SUPPORTED
if the specified message digest type is not available. - DK4_E_SYSTEM
if the underlaying library indicated an error.
Note: iDetails is not set to an errno value. */ int dk4md_ctx_init(dk4_md_ctx_t *ctxptr, int mdt, int mde, dk4_er_t *erp); /** Add bytes to CTX. @param ctxptr CTX structure. @param buffer Start address of buffer containing bytes to add. @param sz Buffer size. @param erp Error report, may be NULL. @return 1 on success 0 on error. Error codes: - DK4_E_INVALID_ARGUMENTS
if ctxptr or buffer is NULL or sz is 0 or sz exceeds the range for unsigned long, - DK4_E_SYNTAX
if an invalid value is specified for mdt. - DK4_E_NOT_SUPPORTED
if the specified message digest type is not available. - DK4_E_SYSTEM
if the underlaying library indicated an error.
Note: iDetails is not set to an errno value. */ int dk4md_ctx_add( dk4_md_ctx_t *ctxptr, const void *buffer, size_t sz, dk4_er_t *erp ); /** Finish checksum and create text representation. @param rptr Address of pointer variable for result buffer, the variable should be initialized to NULL. @param rszptr Address of size variable for result buffer, the variable should be initialized to 0. @param ctxptr CTX structure. @param erp Error report, may be NULL. @return 1 on success, 0 on error. Error codes: - DK4_E_INVALID_ARGUMENTS
if rptr, rszptr, or ctxptr is NULL, - DK4_E_NOT_SUPPORTED
if the specified message digest type is not available. */ int dk4md_ctx_finish( const char **rptr, size_t *rszptr, dk4_md_ctx_t *ctxptr, dk4_er_t *erp ); /** Find message digest size (number of binary bytes or text characters without finalizing 0 byte). @param mdt Message digest type, one from: DK4_MD_MD5, DK4_MD_SHA1, DK4_MD_SHA224, DK4_MD_SHA256, DK4_MD_SHA384, DK4_MD_SHA512, or DK4_MD_RIPEMD_160. @param mde Message digest encoding, one from: DK4_BINARY_TO_TEXT_ENCODING_NONE, DK4_BINARY_TO_TEXT_ENCODING_HEX, or DK4_BINARY_TO_TEXT_ENCODING_A85. @param erp Error report, may be NULL. @return Number of bytes or text characters on success, 0 on error. Error codes: - DK4_E_INVALID_ARGUMENTS
for illegal mdt or mde values. */ size_t dk4md_size(int mdt, int mde, dk4_er_t *erp); /** Find numeric message digest type for string. @param name Message digest type name. @param erp Error report, may be NULL. @return Non-negative message digest type on success, -1 on error. Error codes: - DK4_E_INVALID_ARGUMENTS
if name is NULL, - DK4_E_SYNTAX
if name is not a valid message digest type name. */ int dk4md_choose_type(const dkChar *name, dk4_er_t *erp); /** Check whether support for a message type is available. @param mdtype Message type to check for. @return 1 if supported, 0 otherwise. */ int dk4md_check_type(int mdtype); #ifdef __cplusplus } #endif /** Message digest types. */ enum { /** MD5. */ DK4_MD_MD5 = 0 , /** SHA-1. */ DK4_MD_SHA1 , /** SHA-224. */ DK4_MD_SHA224 , /** SHA-256. */ DK4_MD_SHA256 , /** SHA-384. */ DK4_MD_SHA384 , /** SHA-512. */ DK4_MD_SHA512 , /** RIPEMD-160. */ DK4_MD_RIPEMD_160 }; %% module #include "dk4md.h" #include "dk4mem.h" #include "dk4numco.h" #include "dk4binenc.h" $!trace-include int dk4md_ctx_init(dk4_md_ctx_t *ctxptr, int mdt, int mde, dk4_er_t *erp) { int back = 0; if (NULL != ctxptr) { DK4_MEMRES(ctxptr, sizeof(dk4_md_ctx_t)); ctxptr->mdtype = -1; ctxptr->encoding = -1; switch (mde) { case DK4_BINARY_TO_TEXT_ENCODING_HEX: case DK4_BINARY_TO_TEXT_ENCODING_A85: { ctxptr->encoding = mde; } break; default : { dk4error_set_simple_error_code(erp, DK4_E_SYNTAX); } break; } if (-1 != ctxptr->encoding) { switch (mdt) { case DK4_MD_MD5 : { #if DK4_HAVE_OPENSSL_MD5_H ctxptr->mdtype = mdt; if (1 == MD5_Init(&((ctxptr->ctx).md5))) { back = 1; } else { dk4error_set_simple_error_code(erp, DK4_E_SYSTEM); } #else dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED); #endif } break; case DK4_MD_SHA1 : { #if DK4_HAVE_OPENSSL_SHA_H ctxptr->mdtype = mdt; if (1 == SHA1_Init(&((ctxptr->ctx).sha))) { back = 1; } else { dk4error_set_simple_error_code(erp, DK4_E_SYSTEM); } #else dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED); #endif } break; case DK4_MD_SHA224 : { #if DK4_HAVE_OPENSSL_SHA_H && DK4_HAVE_SHA224 ctxptr->mdtype = mdt; if (1 == SHA224_Init(&((ctxptr->ctx).sha256))) { back = 1; } else { dk4error_set_simple_error_code(erp, DK4_E_SYSTEM); } #else dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED); #endif } break; case DK4_MD_SHA256 : { #if DK4_HAVE_OPENSSL_SHA_H && DK4_HAVE_SHA256 ctxptr->mdtype = mdt; if (1 == SHA256_Init(&((ctxptr->ctx).sha256))) { back = 1; } else { dk4error_set_simple_error_code(erp, DK4_E_SYSTEM); } #else dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED); #endif } break; case DK4_MD_SHA384 : { #if DK4_HAVE_OPENSSL_SHA_H && DK4_HAVE_SHA384 ctxptr->mdtype = mdt; if (1 == SHA384_Init(&((ctxptr->ctx).sha512))) { back = 1; } else { dk4error_set_simple_error_code(erp, DK4_E_SYSTEM); } #else dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED); #endif } break; case DK4_MD_SHA512 : { #if DK4_HAVE_OPENSSL_SHA_H && DK4_HAVE_SHA512 ctxptr->mdtype = mdt; if (1 == SHA512_Init(&((ctxptr->ctx).sha512))) { back = 1; } else { dk4error_set_simple_error_code(erp, DK4_E_SYSTEM); } #else dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED); #endif } break; case DK4_MD_RIPEMD_160 : { #if DK4_HAVE_OPENSSL_RIPEMD_H ctxptr->mdtype = mdt; if (1 == RIPEMD160_Init(&((ctxptr->ctx).ripemd160))) { back = 1; } else { dk4error_set_simple_error_code(erp, DK4_E_SYSTEM); } #else dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED); #endif } break; } } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } return back; } int dk4md_ctx_add( dk4_md_ctx_t *ctxptr, const void *buffer, size_t sz, dk4_er_t *erp ) { int back = 0; if ((NULL != ctxptr) && (NULL != buffer) && (0 < sz)) { if ((dk4_um_t)sz <= (dk4_um_t)ULONG_MAX) { if (-1 != ctxptr->mdtype) { switch (ctxptr->mdtype) { case DK4_MD_MD5 : { #if DK4_HAVE_OPENSSL_MD5_H back = MD5_Update( &((ctxptr->ctx).md5), buffer, (unsigned long)sz ); if (0 == back) { dk4error_set_simple_error_code(erp, DK4_E_SYSTEM); } #else dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED); #endif } break; case DK4_MD_SHA1 : { #if DK4_HAVE_OPENSSL_SHA_H back = SHA1_Update( &((ctxptr->ctx).sha), buffer, (unsigned long)sz ); if (0 == back) { dk4error_set_simple_error_code(erp, DK4_E_SYSTEM); } #else dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED); #endif } break; case DK4_MD_SHA224 : { #if DK4_HAVE_OPENSSL_SHA_H && DK4_HAVE_SHA224 back = SHA224_Update( &((ctxptr->ctx).sha256), buffer, (unsigned long)sz ); if (0 == back) { dk4error_set_simple_error_code(erp, DK4_E_SYSTEM); } #else dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED); #endif } break; case DK4_MD_SHA256 : { #if DK4_HAVE_OPENSSL_SHA_H && DK4_HAVE_SHA256 back = SHA256_Update( &((ctxptr->ctx).sha256), buffer, (unsigned long)sz ); if (0 == back) { dk4error_set_simple_error_code(erp, DK4_E_SYSTEM); } #else dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED); #endif } break; case DK4_MD_SHA384 : { #if DK4_HAVE_OPENSSL_SHA_H && DK4_HAVE_SHA384 back = SHA384_Update( &((ctxptr->ctx).sha512), buffer, (unsigned long)sz ); if (0 == back) { dk4error_set_simple_error_code(erp, DK4_E_SYSTEM); } #else dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED); #endif } break; case DK4_MD_SHA512 : { #if DK4_HAVE_OPENSSL_SHA_H && DK4_HAVE_SHA512 back = SHA512_Update( &((ctxptr->ctx).sha512), buffer, (unsigned long)sz ); if (0 == back) { dk4error_set_simple_error_code(erp, DK4_E_SYSTEM); } #else dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED); #endif } break; case DK4_MD_RIPEMD_160 : { #if DK4_HAVE_OPENSSL_RIPEMD_H back = RIPEMD160_Update( &((ctxptr->ctx).ripemd160), buffer, (unsigned long)sz ); if (0 == back) { dk4error_set_simple_error_code(erp, DK4_E_SYSTEM); } #else dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED); #endif } break; default : { dk4error_set_simple_error_code(erp, DK4_E_SYNTAX); } break; } } else { dk4error_set_simple_error_code(erp, DK4_E_SYNTAX); } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } return back; } int dk4md_ctx_finish( const char **rptr, size_t *rszptr, dk4_md_ctx_t *ctxptr, dk4_er_t *erp ) { int back = 0; $? "+ dk4md_ctx_finish" if ((NULL != rptr) && (NULL != rszptr) && (NULL != ctxptr)) { if (-1 != ctxptr->mdtype) { switch (ctxptr->mdtype) { case DK4_MD_MD5 : { #if DK4_HAVE_OPENSSL_MD5_H back = MD5_Final(&(ctxptr->bbuf[0]), &((ctxptr->ctx).md5)); if (0 != back) { back = dk4binenc( &(ctxptr->obuf[0]), DK4MD_BUFFER_SIZE_TEXT, &(ctxptr->bbuf[0]), 16, ctxptr->encoding, erp ); if (0 != back) { *rptr = &(ctxptr->obuf[0]); switch (ctxptr->encoding) { case DK4_BINARY_TO_TEXT_ENCODING_NONE : { *rszptr = 16; } break; case DK4_BINARY_TO_TEXT_ENCODING_HEX : { *rszptr = 32; } break; case DK4_BINARY_TO_TEXT_ENCODING_A85 : { *rszptr = 20; } break; } } } else { dk4error_set_simple_error_code(erp, DK4_E_SYSTEM); } #else dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED); #endif } break; case DK4_MD_SHA1 : { #if DK4_HAVE_OPENSSL_SHA_H back = SHA1_Final(&(ctxptr->bbuf[0]), &((ctxptr->ctx).sha)); if (0 != back) { back = dk4binenc( &(ctxptr->obuf[0]), DK4MD_BUFFER_SIZE_TEXT, &(ctxptr->bbuf[0]), 20, ctxptr->encoding, erp ); if (0 != back) { *rptr = &(ctxptr->obuf[0]); switch (ctxptr->encoding) { case DK4_BINARY_TO_TEXT_ENCODING_NONE : { *rszptr = 20; } break; case DK4_BINARY_TO_TEXT_ENCODING_HEX : { *rszptr = 40; } break; case DK4_BINARY_TO_TEXT_ENCODING_A85 : { *rszptr = 25; } break; } } } else { dk4error_set_simple_error_code(erp, DK4_E_SYSTEM); } #else dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED); #endif } break; case DK4_MD_SHA224 : { #if DK4_HAVE_OPENSSL_SHA_H && DK4_HAVE_SHA224 back = SHA224_Final(&(ctxptr->bbuf[0]), &((ctxptr->ctx).sha256)); if (0 != back) { back = dk4binenc( &(ctxptr->obuf[0]), DK4MD_BUFFER_SIZE_TEXT, &(ctxptr->bbuf[0]), 28, ctxptr->encoding, erp ); if (0 != back) { *rptr = &(ctxptr->obuf[0]); switch (ctxptr->encoding) { case DK4_BINARY_TO_TEXT_ENCODING_NONE : { *rszptr = 28; } break; case DK4_BINARY_TO_TEXT_ENCODING_HEX : { *rszptr = 56; } break; case DK4_BINARY_TO_TEXT_ENCODING_A85 : { *rszptr = 35; } break; } } } else { dk4error_set_simple_error_code(erp, DK4_E_SYSTEM); } #else dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED); #endif } break; case DK4_MD_SHA256 : { #if DK4_HAVE_OPENSSL_SHA_H && DK4_HAVE_SHA256 back = SHA256_Final(&(ctxptr->bbuf[0]), &((ctxptr->ctx).sha256)); if (0 != back) { back = dk4binenc( &(ctxptr->obuf[0]), DK4MD_BUFFER_SIZE_TEXT, &(ctxptr->bbuf[0]), 32, ctxptr->encoding, erp ); if (0 != back) { *rptr = &(ctxptr->obuf[0]); switch (ctxptr->encoding) { case DK4_BINARY_TO_TEXT_ENCODING_NONE : { *rszptr = 32; } break; case DK4_BINARY_TO_TEXT_ENCODING_HEX : { *rszptr = 64; } break; case DK4_BINARY_TO_TEXT_ENCODING_A85 : { *rszptr = 40; } break; } } } else { dk4error_set_simple_error_code(erp, DK4_E_SYSTEM); } #else dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED); #endif } break; case DK4_MD_SHA384 : { #if DK4_HAVE_OPENSSL_SHA_H && DK4_HAVE_SHA384 back = SHA384_Final(&(ctxptr->bbuf[0]), &((ctxptr->ctx).sha512)); if (0 != back) { back = dk4binenc( &(ctxptr->obuf[0]), DK4MD_BUFFER_SIZE_TEXT, &(ctxptr->bbuf[0]), 48, ctxptr->encoding, erp ); if (0 != back) { *rptr = &(ctxptr->obuf[0]); switch (ctxptr->encoding) { case DK4_BINARY_TO_TEXT_ENCODING_NONE : { *rszptr = 48; } break; case DK4_BINARY_TO_TEXT_ENCODING_HEX : { *rszptr = 96; } break; case DK4_BINARY_TO_TEXT_ENCODING_A85 : { *rszptr = 60; } break; } } } else { dk4error_set_simple_error_code(erp, DK4_E_SYSTEM); } #else dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED); #endif } break; case DK4_MD_SHA512 : { $? ". sha-512 wanted" #if DK4_HAVE_OPENSSL_SHA_H && DK4_HAVE_SHA512 $? ". sha-512 supported" back = SHA512_Final(&(ctxptr->bbuf[0]), &((ctxptr->ctx).sha512)); if (0 != back) { $? ". SHA512_Final()" back = dk4binenc( &(ctxptr->obuf[0]), DK4MD_BUFFER_SIZE_TEXT, &(ctxptr->bbuf[0]), 64, ctxptr->encoding, erp ); if (0 != back) { $? ". dk4binenc" *rptr = &(ctxptr->obuf[0]); $? ". setting pointer" switch (ctxptr->encoding) { case DK4_BINARY_TO_TEXT_ENCODING_NONE : { *rszptr = 64; } break; case DK4_BINARY_TO_TEXT_ENCODING_HEX : { *rszptr = 128;} break; case DK4_BINARY_TO_TEXT_ENCODING_A85 : { *rszptr = 80; } break; } } else { $? "! dk4binenc" } } else { $? "! SHA512_Final()" dk4error_set_simple_error_code(erp, DK4_E_SYSTEM); } #else dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED); #endif } break; case DK4_MD_RIPEMD_160 : { #if DK4_HAVE_OPENSSL_RIPEMD_H back = RIPEMD160_Final(&(ctxptr->bbuf[0]),&((ctxptr->ctx).ripemd160)); if (0 != back) { back = dk4binenc( &(ctxptr->obuf[0]), DK4MD_BUFFER_SIZE_TEXT, &(ctxptr->bbuf[0]), 20, ctxptr->encoding, erp ); if (0 != back) { *rptr = &(ctxptr->obuf[0]); switch (ctxptr->encoding) { case DK4_BINARY_TO_TEXT_ENCODING_NONE : { *rszptr = 20; } break; case DK4_BINARY_TO_TEXT_ENCODING_HEX : { *rszptr = 40; } break; case DK4_BINARY_TO_TEXT_ENCODING_A85 : { *rszptr = 25; } break; } } } else { dk4error_set_simple_error_code(erp, DK4_E_SYSTEM); } #else dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED); #endif } break; default : { /* ERROR: Wrong MD type */ dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED); } break; } } else { /* ERROR Wrong MD type */ dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED); } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } $? "- dk4md_ctx_finish %d", back return back; } size_t dk4md_size(int mdt, int mde, dk4_er_t *erp) { size_t back = 0; switch (mdt) { case DK4_MD_MD5 : { switch (mde) { case DK4_BINARY_TO_TEXT_ENCODING_NONE : { back = 16; } break; case DK4_BINARY_TO_TEXT_ENCODING_HEX : { back = 32; } break; case DK4_BINARY_TO_TEXT_ENCODING_A85 : { back = 20; } break; } } break; case DK4_MD_SHA1 : case DK4_MD_RIPEMD_160 : { switch (mde) { case DK4_BINARY_TO_TEXT_ENCODING_NONE : { back = 20; } break; case DK4_BINARY_TO_TEXT_ENCODING_HEX : { back = 40; } break; case DK4_BINARY_TO_TEXT_ENCODING_A85 : { back = 25; } break; } } break; case DK4_MD_SHA224 : { switch (mde) { case DK4_BINARY_TO_TEXT_ENCODING_NONE : { back = 28; } break; case DK4_BINARY_TO_TEXT_ENCODING_HEX : { back = 56; } break; case DK4_BINARY_TO_TEXT_ENCODING_A85 : { back = 35; } break; } } break; case DK4_MD_SHA256 : { switch (mde) { case DK4_BINARY_TO_TEXT_ENCODING_NONE : { back = 32; } break; case DK4_BINARY_TO_TEXT_ENCODING_HEX : { back = 64; } break; case DK4_BINARY_TO_TEXT_ENCODING_A85 : { back = 40; } break; } } break; case DK4_MD_SHA384 : { switch (mde) { case DK4_BINARY_TO_TEXT_ENCODING_NONE : { back = 48; } break; case DK4_BINARY_TO_TEXT_ENCODING_HEX : { back = 96; } break; case DK4_BINARY_TO_TEXT_ENCODING_A85 : { back = 60; } break; } } break; case DK4_MD_SHA512 : { switch (mde) { case DK4_BINARY_TO_TEXT_ENCODING_NONE : { back = 64; } break; case DK4_BINARY_TO_TEXT_ENCODING_HEX : { back = 128; } break; case DK4_BINARY_TO_TEXT_ENCODING_A85 : { back = 80; } break; } } break; } if (0 == back) { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } return back; }