Commit bdd54648 authored by Yury Popov's avatar Yury Popov Committed by Marcel Stör
Browse files

Upgrade to SDK 2.0.0 (#1435)

* Update LWIP from SDK
* mbedTLS integration
* Fix argument type in dbg_printf (#1624)
* Migrate to espressif’s download center (#1604)
* Fixed BBS links to firmware
* Adjust net module docs with mbedTLS info
* Remove unrelevant axTLS notice
parent 017b4637
#include "c_types.h"
#include "mem.h"
#include "user_interface.h"
void *espconn_memzalloc(size_t size, char* file, int line)
{
void *mp = NULL;
if ((mp = (void*)os_malloc(size)) == NULL){
} else{
//os_printf("%s %d %p %d\n",file, line, mp, size);
os_memset(mp, 0, size);
}
return mp;
}
void espconn_memfree(void *fp, char* file, int line)
{
//os_printf("%s %d %p\n",file, line, fp);
os_free(fp);
fp = NULL;
}
void *espconn_memcpy(void *dst, const void *src, size_t size, char *file, int line)
{
char *psrc = NULL;
char *pdst = NULL;
if(NULL == dst || NULL == src)
{
return NULL;
}
//os_printf("%s %d %p %p %d\n",file, line, dst, src, size);
if((src < dst) && (char *)src + size > (char *)dst)
{
psrc = (char *)src + size - 1;
pdst = (char *)dst + size - 1;
while(size--)
{
*pdst-- = *psrc--;
}
}
else
{
psrc = (char *)src;
pdst = (char *)dst;
while(size--)
{
*pdst++ = *psrc++;
}
}
return dst;
}
void *espconn_memcalloc(size_t count, size_t size)
{
void *cp = NULL;
cp = espconn_memzalloc(count * size, __FILE__, __LINE__);
return cp;
}
void espconn_memFree(void *fp)
{
espconn_memfree(fp, __FILE__, __LINE__);
}
void *espconn_memCpy(void *dst, const void *src, size_t size)
{
return espconn_memcpy(dst, src, size, __FILE__, __LINE__);
}
#############################################################
# Required variables for each makefile
# Discard this section from all parent makefiles
# Expected variables (with automatic defaults):
# CSRCS (all "C" files in the dir)
# SUBDIRS (all subdirs with a Makefile)
# GEN_LIBS - list of libs to be generated ()
# GEN_IMAGES - list of images to be generated ()
# COMPONENTS_xxx - a list of libs/objs in the form
# subdir/lib to be extracted and rolled up into
# a generated lib/image xxx.a ()
#
ifndef PDIR
GEN_LIBS = libapp.a
endif
#############################################################
# Configuration i.e. compile options etc.
# Target specific stuff (defines etc.) goes in here!
# Generally values applying to a tree are captured in the
# makefile at its root level - these are then overridden
# for a subtree within the makefile rooted therein
#
#DEFINES +=
#############################################################
# Recursion Magic - Don't touch this!!
#
# Each subtree potentially has an include directory
# corresponding to the common APIs applicable to modules
# rooted at that subtree. Accordingly, the INCLUDE PATH
# of a module can only contain the include directories up
# its parent path, and not its siblings
#
# Required for each makefile to inherit from the parent
#
INCLUDES := $(INCLUDES) -I $(PDIR)include
INCLUDES += -I ./
PDIR := ../$(PDIR)
sinclude $(PDIR)Makefile
/*
* ESPRSSIF MIT License
*
* Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
* it is free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#if !defined(ESPCONN_MBEDTLS)
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#include "mbedtls/ssl_internal.h"
#include "mem.h"
#ifdef MEMLEAK_DEBUG
static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;
#endif
#include "sys/socket.h"
#include "sys/espconn_mbedtls.h"
static os_event_t lwIPThreadQueue[lwIPThreadQueueLen];
static bool lwIPThreadFlag = false;
extern espconn_msg *plink_active;
static espconn_msg *plink_server = NULL;
static pmbedtls_parame def_certificate = NULL;
static pmbedtls_parame def_private_key = NULL;
#if defined(ESP8266_PLATFORM)
#define MBEDTLS_SSL_OUTBUFFER_LEN ( MBEDTLS_SSL_PLAIN_ADD \
+ MBEDTLS_SSL_COMPRESSION_ADD \
+ 29 /* counter + header + IV */ \
+ MBEDTLS_SSL_MAC_ADD \
+ MBEDTLS_SSL_PADDING_ADD \
)
#endif
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n ) {
volatile unsigned char *p = v; while( n-- ) *p++ = 0;
}
static pmbedtls_parame mbedtls_parame_new(size_t capacity)
{
pmbedtls_parame rb = (pmbedtls_parame)os_zalloc(sizeof(mbedtls_parame));
if (rb && capacity != 0){
rb->parame_datalen = capacity;
rb->parame_data = (uint8*)os_zalloc(rb->parame_datalen + 1);
if (rb->parame_data){
} else{
os_free(rb);
rb = NULL;
}
}
return rb;
}
static void mbedtls_parame_free(pmbedtls_parame *fp)
{
lwIP_ASSERT(fp);
lwIP_ASSERT(*fp);
os_free((*fp)->parame_data);
os_free(*fp);
*fp = NULL;
}
bool mbedtls_load_default_obj(uint32 flash_sector, int obj_type, const unsigned char *load_buf, uint16 length)
{
pmbedtls_parame mbedtls_write = NULL;
uint32 mbedtls_head = 0;
bool mbedtls_load_flag = false;
if (flash_sector != 0){
spi_flash_read(flash_sector * FLASH_SECTOR_SIZE, (uint32*)&mbedtls_head, 4);
if (mbedtls_head != ESPCONN_INVALID_TYPE){
mbedtls_write = mbedtls_parame_new(0);
mbedtls_write->parame_datalen = length;
}
} else{
const char* const begin = "-----BEGIN";
int format_type = ESPCONN_FORMAT_INIT;
/*
* Determine data content. data contains either one DER certificate or
* one or more PEM certificates.
*/
if ((char*)os_strstr(load_buf, begin) != NULL){
format_type = ESPCONN_FORMAT_PEM;
}else{
format_type = ESPCONN_FORMAT_DER;
}
if (format_type == ESPCONN_FORMAT_PEM){
length += 1;
}
mbedtls_write = mbedtls_parame_new(length);
if (mbedtls_write){
os_memcpy(mbedtls_write->parame_data, load_buf, length);
if (format_type == ESPCONN_FORMAT_PEM)
mbedtls_write->parame_data[length - 1] = '\0';
}
}
if (mbedtls_write){
mbedtls_load_flag = true;
mbedtls_write->parame_type = obj_type;
mbedtls_write->parame_sec = flash_sector;
if (obj_type == ESPCONN_PK){
def_private_key = mbedtls_write;
} else{
def_certificate = mbedtls_write;
}
}
return mbedtls_load_flag;
}
static unsigned char* mbedtls_get_default_obj(uint32 *sec, uint32 type, uint32 *len)
{
const char* const begin = "-----BEGIN";
unsigned char *parame_data = NULL;
pmbedtls_parame mbedtls_obj = NULL;
if (type == ESPCONN_PK){
mbedtls_obj = def_private_key;
} else{
mbedtls_obj = def_certificate;
}
if (mbedtls_obj->parame_sec != 0){
#define DATA_OFFSET 4
uint32 data_len = mbedtls_obj->parame_datalen;
parame_data = (unsigned char *)os_zalloc(data_len + DATA_OFFSET);
if (parame_data){
spi_flash_read(mbedtls_obj->parame_sec * FLASH_SECTOR_SIZE, (uint32*)parame_data, data_len);
/*
* Determine buffer content. Buffer contains either one DER certificate or
* one or more PEM certificates.
*/
if ((char*)os_strstr(parame_data, begin) != NULL){
data_len ++;
parame_data[data_len - 1] = '\0';
}
}
*len = data_len;
} else{
parame_data = mbedtls_obj->parame_data;
*len = mbedtls_obj->parame_datalen;
}
*sec = mbedtls_obj->parame_sec;
return parame_data;
}
static int mbedtls_setsockopt(int sock_id, int level, int optname, int optval)
{
return setsockopt(sock_id, level, optname, (void*)&optval, sizeof(optval));
}
static int mbedtls_keep_alive(int sock_id, int onoff, int idle, int intvl, int cnt)
{
int ret = ERR_OK;
if (onoff == 0)
return mbedtls_setsockopt(sock_id, SOL_SOCKET, SO_KEEPALIVE, onoff);;
ret = mbedtls_setsockopt(sock_id, SOL_SOCKET, SO_KEEPALIVE, onoff);
lwIP_REQUIRE_NOERROR(ret, exit);
ret = mbedtls_setsockopt(sock_id, IPPROTO_TCP, TCP_KEEPALIVE, onoff);
lwIP_REQUIRE_NOERROR(ret, exit);
ret = mbedtls_setsockopt(sock_id, IPPROTO_TCP, TCP_KEEPIDLE, idle);
lwIP_REQUIRE_NOERROR(ret, exit);
ret = mbedtls_setsockopt(sock_id, IPPROTO_TCP, TCP_KEEPINTVL, intvl);
lwIP_REQUIRE_NOERROR(ret, exit);
ret = mbedtls_setsockopt(sock_id, IPPROTO_TCP, TCP_KEEPCNT, cnt);
lwIP_REQUIRE_NOERROR(ret, exit);
exit:
return ret;
}
#if defined(ESP8266_PLATFORM)
static pmbedtls_finished mbedtls_finished_new(int len)
{
pmbedtls_finished finished = (pmbedtls_finished)os_zalloc(sizeof(mbedtls_finished));
if (finished)
{
finished->finished_len = len;
finished->finished_buf = (uint8*)os_zalloc(finished->finished_len + 1);
if (finished->finished_buf)
{
}
else
{
os_free(finished);
finished = NULL;
}
}
return finished;
}
static void mbedtls_finished_free(pmbedtls_finished *pfinished)
{
lwIP_ASSERT(pfinished);
lwIP_ASSERT(*pfinished);
os_free((*pfinished)->finished_buf);
os_free(*pfinished);
*pfinished = NULL;
}
#endif
static pmbedtls_espconn mbedtls_espconn_new(void)
{
pmbedtls_espconn mbedtls_conn = NULL;
mbedtls_conn = (pmbedtls_espconn)os_zalloc(sizeof(mbedtls_espconn));
if (mbedtls_conn){
mbedtls_conn->proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp));
if (mbedtls_conn->proto.tcp == NULL){
os_free(mbedtls_conn);
mbedtls_conn = NULL;
}
}
return mbedtls_conn;
}
static void mbedtls_espconn_free(pmbedtls_espconn *mbedtlsconn)
{
lwIP_ASSERT(mbedtlsconn);
lwIP_ASSERT(*mbedtlsconn);
os_free((*mbedtlsconn)->proto.tcp);
(*mbedtlsconn)->proto.tcp = NULL;
os_free((*mbedtlsconn));
*mbedtlsconn = NULL;
}
static pmbedtls_session mbedtls_session_new(void)
{
pmbedtls_session session = (pmbedtls_session)os_zalloc(sizeof(mbedtls_session));
if (session){
mbedtls_x509_crt_init(&session->cacert);
mbedtls_x509_crt_init(&session->clicert);
mbedtls_pk_init(&session->pkey);
// mbedtls_entropy_init(&session->entropy);
}
return session;
}
static void mbedtls_session_free(pmbedtls_session *session)
{
lwIP_ASSERT(session);
lwIP_ASSERT(*session);
mbedtls_x509_crt_free(&(*session)->cacert);
mbedtls_x509_crt_free(&(*session)->clicert);
mbedtls_pk_free(&(*session)->pkey);
// mbedtls_entropy_free(&(*session)->entropy);
os_free(*session);
*session = NULL;
}
static pmbedtls_msg mbedtls_msg_new(void)
{
pmbedtls_msg msg = (pmbedtls_msg)os_zalloc( sizeof(mbedtls_msg));
if (msg) {
os_bzero(msg, sizeof(mbedtls_msg));
msg->psession = mbedtls_session_new();
if (msg->psession){
mbedtls_net_init(&msg->listen_fd);
mbedtls_net_init(&msg->fd);
mbedtls_ssl_init(&msg->ssl);
mbedtls_ssl_config_init(&msg->conf);
mbedtls_ctr_drbg_init(&msg->ctr_drbg);
mbedtls_entropy_init(&msg->entropy);
} else{
os_free(msg);
msg = NULL;
}
}
return msg;
}
static void mbedtls_msg_server_step(pmbedtls_msg msg)
{
lwIP_ASSERT(msg);
/*to prevent memory leaks, ensure that each allocated is deleted at every handshake*/
if (msg->psession){
mbedtls_session_free(&msg->psession);
}
#if defined(ESP8266_PLATFORM)
if (msg->quiet && msg->ssl.out_buf)
{
mbedtls_zeroize(msg->ssl.out_buf, MBEDTLS_SSL_OUTBUFFER_LEN);
os_free(msg->ssl.out_buf);
msg->ssl.out_buf = NULL;
}
#endif
mbedtls_entropy_free(&msg->entropy);
mbedtls_ssl_free(&msg->ssl);
mbedtls_ssl_config_free(&msg->conf);
mbedtls_ctr_drbg_free(&msg->ctr_drbg);
/*New connection ensure that each initial for next handshake */
os_bzero(msg, sizeof(mbedtls_msg));
msg->psession = mbedtls_session_new();
if (msg->psession){
mbedtls_net_init(&msg->fd);
mbedtls_ssl_init(&msg->ssl);
mbedtls_ssl_config_init(&msg->conf);
mbedtls_ctr_drbg_init(&msg->ctr_drbg);
mbedtls_entropy_init(&msg->entropy);
}
}
static void mbedtls_msg_free(pmbedtls_msg *msg)
{
lwIP_ASSERT(msg);
lwIP_ASSERT(*msg);
/*to prevent memory leaks, ensure that each allocated is deleted at every handshake*/
if ((*msg)->psession){
mbedtls_session_free(&((*msg)->psession));
}
#if defined(ESP8266_PLATFORM)
if ((*msg)->quiet && (*msg)->ssl.out_buf)
{
mbedtls_zeroize((*msg)->ssl.out_buf, MBEDTLS_SSL_OUTBUFFER_LEN);
os_free((*msg)->ssl.out_buf);
(*msg)->ssl.out_buf = NULL;
}
#endif
mbedtls_entropy_free(&(*msg)->entropy);
mbedtls_ssl_free(&(*msg)->ssl);
mbedtls_ssl_config_free(&(*msg)->conf);
mbedtls_ctr_drbg_free(&(*msg)->ctr_drbg);
os_free(*msg);
*msg = NULL;
}
static espconn_msg* mbedtls_msg_find(int sock)
{
espconn_msg *plist = NULL;
pmbedtls_msg msg = NULL;
for (plist = plink_active; plist != NULL; plist = plist->pnext) {
if(plist->pssl != NULL){
msg = plist->pssl;
if (msg->fd.fd == sock)
return plist;
}
}
for (plist = plink_server; plist != NULL; plist = plist->pnext){
if(plist->pssl != NULL){
msg = plist->pssl;
if (msg->listen_fd.fd == sock)
return plist;
}
}
return NULL;
}
void mbedtls_handshake_heap(mbedtls_ssl_context *ssl)
{
os_printf("mbedtls_handshake_heap %d %d\n", ssl->state, system_get_free_heap_size());
}
static bool mbedtls_handshake_result(const pmbedtls_msg Threadmsg)
{
if (Threadmsg == NULL)
return false;
if (Threadmsg->ssl.state == MBEDTLS_SSL_HANDSHAKE_OVER) {
int ret = 0;
if (Threadmsg->listen_fd.fd == -1)
ret = ssl_option.client.cert_ca_sector.flag;
else
ret = ssl_option.server.cert_ca_sector.flag;
if (ret == 1){
ret = mbedtls_ssl_get_verify_result(&Threadmsg->ssl);
if (ret != 0) {
char vrfy_buf[512];
os_memset(vrfy_buf, 0, sizeof(vrfy_buf)-1);
mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), "!", ret);
os_printf("%s\n", vrfy_buf);
Threadmsg->verify_result = ret;
return false;
} else
return true;
} else
return true;
}else
return false;
}
static void mbedtls_fail_info(espconn_msg *pinfo, int ret)
{
pmbedtls_msg TLSmsg = NULL;
lwIP_REQUIRE_ACTION(pinfo,exit,ret = ERR_ARG);
TLSmsg = pinfo->pssl;
lwIP_REQUIRE_ACTION(TLSmsg,exit,ret = ERR_ARG);
if (TLSmsg->quiet){
if (pinfo->preverse != NULL) {
os_printf("server's data invalid protocol\n");
} else {
os_printf("client's data invalid protocol\n");
}
mbedtls_ssl_close_notify(&TLSmsg->ssl);
} else{
if (pinfo->preverse != NULL) {
os_printf("server handshake failed!\n");
} else {
os_printf("client handshake failed!\n");
}
}
os_printf("Reason:[-0x%2x]\n",-ret);
/*Error code convert*/
ret = -ret;
if ((ret & 0xFF) != 0){
ret = ((ret >> 8) + ret);
} else{
ret >>= 8;
}
pinfo->hs_status = -ret;
pinfo->pespconn->state = ESPCONN_CLOSE;
mbedtls_net_free(&TLSmsg->fd);
exit:
return;
}
#if defined(ESP8266_PLATFORM)
int mbedtls_write_finished(mbedtls_ssl_context *ssl)
{
lwIP_ASSERT(ssl);
lwIP_ASSERT(ssl->p_bio);
int ret = ERR_OK;
int fd = ((mbedtls_net_context *) ssl->p_bio)->fd;
espconn_msg *Threadmsg = mbedtls_msg_find(fd);
lwIP_REQUIRE_ACTION(Threadmsg, exit, ret = ERR_MEM);
pmbedtls_msg TLSmsg = Threadmsg->pssl;
lwIP_REQUIRE_ACTION(TLSmsg, exit, ret = ERR_MEM);
TLSmsg->pfinished = mbedtls_finished_new(ssl->out_msglen + 29);
lwIP_REQUIRE_ACTION(TLSmsg->pfinished, exit, ret = ERR_MEM);
os_memcpy(TLSmsg->pfinished->finished_buf, ssl->out_ctr, TLSmsg->pfinished->finished_len);
exit:
return ret;
}
static int mbedtls_hanshake_finished(mbedtls_msg *msg)
{
lwIP_ASSERT(msg);
int ret = ERR_OK;
const size_t len = MBEDTLS_SSL_OUTBUFFER_LEN;
mbedtls_ssl_context *ssl = &msg->ssl;
lwIP_REQUIRE_ACTION(ssl, exit, ret = ERR_MEM);
pmbedtls_finished finished = msg->pfinished;
lwIP_REQUIRE_ACTION(finished, exit, ret = ERR_MEM);
ssl->out_buf = (unsigned char*)os_zalloc(len);
lwIP_REQUIRE_ACTION(ssl->out_buf, exit, ret = MBEDTLS_ERR_SSL_ALLOC_FAILED);
ssl->out_ctr = ssl->out_buf;
ssl->out_hdr = ssl->out_buf + 8;
ssl->out_len = ssl->out_buf + 11;
ssl->out_iv = ssl->out_buf + 13;
ssl->out_msg = ssl->out_buf + 29;
os_memcpy(ssl->out_ctr, finished->finished_buf, finished->finished_len);
mbedtls_finished_free(&msg->pfinished);
exit:
return ret;
}
#endif
static void mbedtls_handshake_succ(mbedtls_ssl_context *ssl)
{
lwIP_ASSERT(ssl);
if( ssl->handshake )
{
mbedtls_ssl_handshake_free( ssl->handshake );
mbedtls_ssl_transform_free( ssl->transform_negotiate );
mbedtls_ssl_session_free( ssl->session_negotiate );
os_free( ssl->handshake );
os_free( ssl->transform_negotiate );
os_free( ssl->session_negotiate );
ssl->handshake = NULL;
ssl->transform_negotiate = NULL;
ssl->session_negotiate = NULL;
}
if( ssl->session )
{
mbedtls_ssl_session_free( ssl->session );
os_free( ssl->session );
ssl->session = NULL;
}
#if defined(MBEDTLS_X509_CRT_PARSE_C)
if( ssl->hostname != NULL )
{
mbedtls_zeroize( ssl->hostname, os_strlen( ssl->hostname ) );
os_free( ssl->hostname );
ssl->hostname = NULL;
}
#endif
}
/******************************************************************************
* FunctionName : espconn_ssl_reconnect
* Description : reconnect with host
* Parameters : arg -- Additional argument to pass to the callback function
* Returns : none
*******************************************************************************/
static void espconn_close_internal(void *arg, netconn_event event_type)
{
espconn_msg *pssl_recon = arg;
struct espconn *espconn = NULL;
sint8 ssl_reerr = 0;
sint16 hs_status = 0;
lwIP_ASSERT(pssl_recon);
espconn = pssl_recon->preverse;
ssl_reerr = pssl_recon->pcommon.err;
hs_status = pssl_recon->hs_status;
if (espconn != NULL) {
espconn = pssl_recon->preverse;
} else {
espconn = pssl_recon->pespconn;
os_free(pssl_recon);
pssl_recon = NULL;
}
espconn_kill_oldest_pcb();
switch (event_type){
case NETCONN_EVENT_ERROR:
if (hs_status == ESPCONN_OK)
ESPCONN_EVENT_ERROR(espconn, ssl_reerr);
else
ESPCONN_EVENT_ERROR(espconn, hs_status);
break;
case NETCONN_EVENT_CLOSE:
if (hs_status == ESPCONN_OK)
ESPCONN_EVENT_CLOSED(espconn);
else
ESPCONN_EVENT_ERROR(espconn, hs_status);
break;
default:
break;
}
}
/******************************************************************************
* FunctionName : espconn_ssl_read_param_from_flash
* Description : load parameter from flash, toggle use two sector by flag value.
* Parameters : param--the parame point which write the flash
* Returns : none
*******************************************************************************/
static bool espconn_ssl_read_param_from_flash(void *param, uint16 len, int32 offset, mbedtls_auth_info *auth_info)
{
if (param == NULL || (len + offset) > ESPCONN_SECURE_MAX_SIZE) {
return false;
}
uint32 FILE_PARAM_START_SEC = 0x3B;
switch (auth_info->auth_level) {
case ESPCONN_CLIENT:
switch (auth_info->auth_type) {
case ESPCONN_CERT_AUTH:
FILE_PARAM_START_SEC = ssl_option.client.cert_ca_sector.sector;
break;
case ESPCONN_CERT_OWN:
case ESPCONN_PK:
FILE_PARAM_START_SEC = ssl_option.client.cert_req_sector.sector;
break;
default:
return false;
}
break;
case ESPCONN_SERVER:
switch (auth_info->auth_type) {
case ESPCONN_CERT_AUTH:
FILE_PARAM_START_SEC = ssl_option.server.cert_ca_sector.sector;
break;
case ESPCONN_CERT_OWN:
case ESPCONN_PK:
FILE_PARAM_START_SEC = ssl_option.server.cert_req_sector.sector;
break;
default:
return false;
}
break;
default:
return false;
break;
}
spi_flash_read(FILE_PARAM_START_SEC * 4096 + offset, param, len);
return true;
}
static bool mbedtls_msg_info_load(mbedtls_msg *msg, mbedtls_auth_info *auth_info)
{
const char* const begin = "-----BEGIN";
const char* const type_name = "private_key";
#define FILE_OFFSET 4
int ret = 0;
int32 offerset = 0;
uint8* load_buf = NULL;
size_t load_len = 0;
file_param *pfile_param = NULL;
pfile_param = (file_param *)os_zalloc( sizeof(file_param));
if (pfile_param==NULL)
return false;
again:
espconn_ssl_read_param_from_flash(&pfile_param->file_head, sizeof(file_head), offerset, auth_info);
pfile_param->file_offerset = offerset;
os_printf("%s %d, type[%s],length[%d]\n", __FILE__, __LINE__, pfile_param->file_head.file_name, pfile_param->file_head.file_length);
if (pfile_param->file_head.file_length == 0xFFFF){
os_free(pfile_param);
return false;
} else{
/*Optional is load the private key*/
if (auth_info->auth_type == ESPCONN_PK && os_memcmp(pfile_param->file_head.file_name, type_name, os_strlen(type_name)) != 0){
offerset += sizeof(file_head) + pfile_param->file_head.file_length;
goto again;
}
load_buf = (uint8_t *) os_zalloc( pfile_param->file_head.file_length + FILE_OFFSET);
if (load_buf == NULL){
os_free(pfile_param);
return false;
}
offerset = sizeof(file_head) + pfile_param->file_offerset;
espconn_ssl_read_param_from_flash(load_buf, pfile_param->file_head.file_length, offerset, auth_info);
}
load_len = pfile_param->file_head.file_length;
/*
* Determine buffer content. Buffer contains either one DER certificate or
* one or more PEM certificates.
*/
if ((char*)os_strstr(load_buf, begin) != NULL){
load_len += 1;
load_buf[load_len - 1] = '\0';
}
switch (auth_info->auth_type){
case ESPCONN_CERT_AUTH:
/*Optional is not optimal for security*/
ret = mbedtls_x509_crt_parse(&msg->psession->cacert, (const uint8*) load_buf,load_len);
lwIP_REQUIRE_NOERROR(ret, exit);
mbedtls_ssl_conf_authmode(&msg->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
mbedtls_ssl_conf_ca_chain(&msg->conf, &msg->psession->cacert, NULL);
break;
case ESPCONN_CERT_OWN:
ret = mbedtls_x509_crt_parse(&msg->psession->clicert, (const uint8*) load_buf,load_len);
break;
case ESPCONN_PK:
ret = mbedtls_pk_parse_key(&msg->psession->pkey, (const uint8*) load_buf,load_len, NULL, 0);
lwIP_REQUIRE_NOERROR(ret, exit);
ret = mbedtls_ssl_conf_own_cert(&msg->conf, &msg->psession->clicert, &msg->psession->pkey);
break;
}
exit:
os_free(load_buf);
os_free(pfile_param);
if (ret < 0){
return false;
}else{
return true;
}
}
static bool mbedtls_msg_config(mbedtls_msg *msg)
{
const char *pers = NULL;
uint8 auth_type = 0;
bool load_flag = false;
int ret = ESPCONN_OK;
mbedtls_auth_info auth_info;
/*end_point mode*/
if (msg->listen_fd.fd == -1){
pers = "client";
auth_type = MBEDTLS_SSL_IS_CLIENT;
} else {
pers = "server";
auth_type = MBEDTLS_SSL_IS_SERVER;
}
/*Initialize the RNG and the session data*/
ret = mbedtls_ctr_drbg_seed(&msg->ctr_drbg, mbedtls_entropy_func, &msg->entropy, (const unsigned char*) pers, os_strlen(pers));
lwIP_REQUIRE_NOERROR(ret, exit);
if (auth_type == MBEDTLS_SSL_IS_SERVER){
uint32 flash_sector = 0;
/*Load the certificate*/
unsigned int def_certificate_len = 0;unsigned char *def_certificate = NULL;
def_certificate = (unsigned char *)mbedtls_get_default_obj(&flash_sector,ESPCONN_CERT_OWN, &def_certificate_len);
lwIP_REQUIRE_ACTION(def_certificate, exit, ret = MBEDTLS_ERR_SSL_ALLOC_FAILED);
ret = mbedtls_x509_crt_parse(&msg->psession->clicert, (const unsigned char *)def_certificate, def_certificate_len);
if (flash_sector != 0)
os_free(def_certificate);
lwIP_REQUIRE_NOERROR(ret, exit);
/*Load the private RSA key*/
unsigned int def_private_key_len = 0;unsigned char *def_private_key = NULL;
def_private_key = (unsigned char *)mbedtls_get_default_obj(&flash_sector,ESPCONN_PK, &def_private_key_len);
lwIP_REQUIRE_ACTION(def_private_key, exit, ret = MBEDTLS_ERR_SSL_ALLOC_FAILED);
ret = mbedtls_pk_parse_key(&msg->psession->pkey, (const unsigned char *)def_private_key, def_private_key_len, NULL, 0);
if (flash_sector != 0)
os_free(def_private_key);
lwIP_REQUIRE_NOERROR(ret, exit);
ret = mbedtls_ssl_conf_own_cert(&msg->conf, &msg->psession->clicert, &msg->psession->pkey);
lwIP_REQUIRE_NOERROR(ret, exit);
/*Load the trusted CA*/
if (ssl_option.server.cert_ca_sector.flag) {
auth_info.auth_level = ESPCONN_SERVER;
auth_info.auth_type = ESPCONN_CERT_AUTH;
load_flag = mbedtls_msg_info_load(msg, &auth_info);
lwIP_REQUIRE_ACTION(load_flag, exit, ret = ESPCONN_MEM);
}
} else{
/*Load the certificate and private RSA key*/
if (ssl_option.client.cert_req_sector.flag) {
auth_info.auth_level = ESPCONN_CLIENT;
auth_info.auth_type = ESPCONN_CERT_OWN;
load_flag = mbedtls_msg_info_load(msg, &auth_info);
lwIP_REQUIRE_ACTION(load_flag, exit, ret = ESPCONN_MEM);
auth_info.auth_type = ESPCONN_PK;
load_flag = mbedtls_msg_info_load(msg, &auth_info);
lwIP_REQUIRE_ACTION(load_flag, exit, ret = ESPCONN_MEM);
}
/*Load the trusted CA*/
if(ssl_option.client.cert_ca_sector.flag){
auth_info.auth_level = ESPCONN_CLIENT;
auth_info.auth_type = ESPCONN_CERT_AUTH;
load_flag = mbedtls_msg_info_load(msg, &auth_info);
lwIP_REQUIRE_ACTION(load_flag, exit, ret = ESPCONN_MEM);
}
}
/*Setup the stuff*/
ret = mbedtls_ssl_config_defaults(&msg->conf, auth_type, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
lwIP_REQUIRE_NOERROR(ret, exit);
/*OPTIONAL is not optimal for security, but makes interop easier in this session*/
if (auth_type == MBEDTLS_SSL_IS_CLIENT && ssl_option.client.cert_ca_sector.flag == false){
mbedtls_ssl_conf_authmode(&msg->conf, MBEDTLS_SSL_VERIFY_NONE);
}
mbedtls_ssl_conf_rng(&msg->conf, mbedtls_ctr_drbg_random, &msg->ctr_drbg);
mbedtls_ssl_conf_dbg(&msg->conf, NULL, NULL);
ret = mbedtls_ssl_setup(&msg->ssl, &msg->conf);
lwIP_REQUIRE_NOERROR(ret, exit);
mbedtls_ssl_set_bio(&msg->ssl, &msg->fd, mbedtls_net_send, mbedtls_net_recv, NULL);
exit:
if (ret != 0){
return false;
} else{
return true;
}
}
int __attribute__((weak)) mbedtls_parse_internal(int socket, sint8 error)
{
int ret = ERR_OK;
bool config_flag = false;
espconn_msg *Threadmsg = NULL;
pmbedtls_msg TLSmsg = NULL;
Threadmsg = mbedtls_msg_find(socket);
lwIP_REQUIRE_ACTION(Threadmsg, exit, ret = ERR_MEM);
TLSmsg = Threadmsg->pssl;
lwIP_REQUIRE_ACTION(TLSmsg, exit, ret = ERR_MEM);
if (error == ERR_OK){
if (TLSmsg->quiet){
uint8 *TheadBuff = NULL;
size_t ThreadLen = MBEDTLS_SSL_PLAIN_ADD;
TheadBuff = (uint8 *)os_zalloc(ThreadLen + 1);
lwIP_REQUIRE_ACTION(TheadBuff, exit, ret = ERR_MEM);
do {
os_memset(TheadBuff, 0, ThreadLen);
ret = mbedtls_ssl_read(&TLSmsg->ssl, TheadBuff, ThreadLen);
if (ret > 0){
ESPCONN_EVENT_RECV(Threadmsg->pespconn, TheadBuff, ret);
} else{
if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == 0){
ret = ESPCONN_OK;
break;
} else{
break;
}
}
} while(1);
os_free(TheadBuff);
TheadBuff = NULL;
lwIP_REQUIRE_NOERROR(ret, exit);
} else{
if (TLSmsg->ssl.state == MBEDTLS_SSL_HELLO_REQUEST){
if (Threadmsg->preverse != NULL){
struct espconn *accept_conn = NULL;
struct espconn *espconn = Threadmsg->preverse;
struct sockaddr_in name;
socklen_t name_len = sizeof(name);
remot_info *pinfo = NULL;
espconn_get_connection_info(espconn, &pinfo , ESPCONN_SSL);
if (espconn->link_cnt == 0x01)
return ERR_ISCONN;
ret = mbedtls_net_accept(&TLSmsg->listen_fd, &TLSmsg->fd, NULL, 0, NULL);
lwIP_REQUIRE_NOERROR(ret, exit);
accept_conn = mbedtls_espconn_new();
lwIP_REQUIRE_ACTION(accept_conn, exit, ret = ERR_MEM);
Threadmsg->pespconn = accept_conn;
/*get the remote information*/
getpeername(TLSmsg->fd.fd, (struct sockaddr*)&name, &name_len);
Threadmsg->pcommon.remote_port = htons(name.sin_port);
os_memcpy(Threadmsg->pcommon.remote_ip, &name.sin_addr.s_addr, 4);
espconn->proto.tcp->remote_port = htons(name.sin_port);
os_memcpy(espconn->proto.tcp->remote_ip, &name.sin_addr.s_addr, 4);
espconn_copy_partial(accept_conn, espconn);
/*insert the node to the active connection list*/
espconn_list_creat(&plink_active, Threadmsg);
os_printf("server handshake start.\n");
} else{
os_printf("client handshake start.\n");
}
config_flag = mbedtls_msg_config(TLSmsg);
if (config_flag){
// mbedtls_keep_alive(TLSmsg->fd.fd, 1, SSL_KEEP_IDLE, SSL_KEEP_INTVL, SSL_KEEP_CNT);
system_overclock();
} else{
ret = MBEDTLS_ERR_SSL_ALLOC_FAILED;
lwIP_REQUIRE_NOERROR(ret, exit);
}
}
system_soft_wdt_stop();
while ((ret = mbedtls_ssl_handshake(&TLSmsg->ssl)) != 0) {
if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
ret = ESPCONN_OK;
break;
} else{
break;
}
}
system_soft_wdt_restart();
lwIP_REQUIRE_NOERROR(ret, exit);
/**/
TLSmsg->quiet = mbedtls_handshake_result(TLSmsg);
if (TLSmsg->quiet){
if (Threadmsg->preverse != NULL) {
os_printf("server handshake ok!\n");
} else {
os_printf("client handshake ok!\n");
}
// mbedtls_keep_alive(TLSmsg->fd.fd, 0, SSL_KEEP_IDLE, SSL_KEEP_INTVL, SSL_KEEP_CNT);
mbedtls_session_free(&TLSmsg->psession);
mbedtls_handshake_succ(&TLSmsg->ssl);
#if defined(ESP8266_PLATFORM)
mbedtls_hanshake_finished(TLSmsg);
#endif
system_restoreclock();
TLSmsg->SentFnFlag = true;
ESPCONN_EVENT_CONNECTED(Threadmsg->pespconn);
} else{
lwIP_REQUIRE_NOERROR_ACTION(TLSmsg->verify_result, exit, ret = TLSmsg->verify_result);
}
}
} else if (error < 0){
Threadmsg->pcommon.err = error;
Threadmsg->pespconn->state = ESPCONN_CLOSE;
mbedtls_net_free(&TLSmsg->fd);
ets_post(lwIPThreadPrio, NETCONN_EVENT_ERROR, (uint32)Threadmsg);
} else {
ret = MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY;
lwIP_REQUIRE_NOERROR(ret, exit);
}
exit:
if (ret != ESPCONN_OK){
mbedtls_fail_info(Threadmsg, ret);
ets_post(lwIPThreadPrio, NETCONN_EVENT_CLOSE,(uint32)Threadmsg);
}
return ret;
}
int __attribute__((weak)) mbedtls_parse_thread(int socket, int event, int error)
{
int ret = ERR_OK;
espconn_msg *Threadmsg = NULL;
pmbedtls_msg TLSmsg = NULL;
Threadmsg = mbedtls_msg_find(socket);
lwIP_REQUIRE_ACTION(Threadmsg, exit, ret = ERR_MEM);
TLSmsg = Threadmsg->pssl;
lwIP_REQUIRE_ACTION(TLSmsg, exit, ret = ERR_MEM);
if (TLSmsg->quiet){
int out_msglen = TLSmsg->ssl.out_msglen + 5;
if (Threadmsg->pcommon.write_flag)
TLSmsg->record.record_len += error;
if (TLSmsg->record.record_len == out_msglen){
TLSmsg->record.record_len = 0;
Threadmsg->pcommon.write_flag = false;
if (Threadmsg->pcommon.cntr != 0){
espconn_ssl_sent(Threadmsg, Threadmsg->pcommon.ptrbuf, Threadmsg->pcommon.cntr);
} else{
TLSmsg->SentFnFlag = true;
ESPCONN_EVENT_SEND(Threadmsg->pespconn);
}
} else{
}
} else{
}
exit:
return ret;
}
/**
* @brief Api_Thread.
* @param events: contain the Api_Thread processing data
* @retval None
*/
static void
mbedtls_thread(os_event_t *events)
{
int ret = ESP_OK;
bool active_flag = false;
espconn_msg *Threadmsg = NULL;
espconn_msg *ListMsg = NULL;
pmbedtls_msg TLSmsg = NULL;
Threadmsg = (espconn_msg *)events->par;
lwIP_REQUIRE_ACTION(Threadmsg,exit,ret = ERR_ARG);
TLSmsg = Threadmsg->pssl;
lwIP_REQUIRE_ACTION(TLSmsg,exit,ret = ERR_ARG);
lwIP_REQUIRE_ACTION(Threadmsg->pespconn,exit,ret = ERR_ARG);
/*find the active connection*/
for (ListMsg = plink_active; ListMsg != NULL; ListMsg = ListMsg->pnext){
if (Threadmsg == ListMsg){
active_flag = true;
break;
}
}
if (active_flag){
/*remove the node from the active connection list*/
espconn_list_delete(&plink_active, Threadmsg);
if (TLSmsg->listen_fd.fd != -1){
mbedtls_msg_server_step(TLSmsg);
espconn_copy_partial(Threadmsg->preverse, Threadmsg->pespconn);
mbedtls_espconn_free(&Threadmsg->pespconn);
} else{
mbedtls_msg_free(&TLSmsg);
Threadmsg->pssl = NULL;
}
switch (events->sig){
case NETCONN_EVENT_ERROR:
espconn_close_internal(Threadmsg, NETCONN_EVENT_ERROR);
break;
case NETCONN_EVENT_CLOSE:
espconn_close_internal(Threadmsg, NETCONN_EVENT_CLOSE);
break;
default:
break;
}
}
exit:
return;
}
static void mbedtls_threadinit(void)
{
ets_task(mbedtls_thread, lwIPThreadPrio, lwIPThreadQueue, lwIPThreadQueueLen);
lwIPThreadFlag = true;
}
sint8 espconn_ssl_client(struct espconn *espconn)
{
int ret = ESPCONN_OK;
struct ip_addr ipaddr;
const char *server_name = NULL;
const char *server_port = NULL;
espconn_msg *pclient = NULL;
pmbedtls_msg mbedTLSMsg = NULL;
if (lwIPThreadFlag == false)
mbedtls_threadinit();
lwIP_REQUIRE_ACTION(espconn, exit, ret = ESPCONN_ARG);
pclient = (espconn_msg *)os_zalloc( sizeof(espconn_msg));
lwIP_REQUIRE_ACTION(pclient, exit, ret = ESPCONN_MEM);
mbedTLSMsg = mbedtls_msg_new();
lwIP_REQUIRE_ACTION(mbedTLSMsg, exit, ret = ESPCONN_MEM);
IP4_ADDR(&ipaddr, espconn->proto.tcp->remote_ip[0],espconn->proto.tcp->remote_ip[1],
espconn->proto.tcp->remote_ip[2],espconn->proto.tcp->remote_ip[3]);
server_name = ipaddr_ntoa(&ipaddr);
server_port = (const char *)sys_itoa(espconn->proto.tcp->remote_port);
/*start the connection*/
ret = mbedtls_net_connect(&mbedTLSMsg->fd, server_name, server_port, MBEDTLS_NET_PROTO_TCP);
lwIP_REQUIRE_NOERROR_ACTION(ret, exit, ret = ESPCONN_MEM);
espconn->state = ESPCONN_WAIT;
pclient->pespconn = espconn;
pclient->pssl = mbedTLSMsg;
pclient->preverse = NULL;
/*insert the node to the active connection list*/
espconn_list_creat(&plink_active, pclient);
exit:
if (ret != ESPCONN_OK){
if (mbedTLSMsg != NULL)
mbedtls_msg_free(&mbedTLSMsg);
if (pclient != NULL)
os_free(pclient);
}
return ret;
}
/******************************************************************************
* FunctionName : espconn_ssl_server
* Description : as
* Parameters :
* Returns :
*******************************************************************************/
sint8 espconn_ssl_server(struct espconn *espconn)
{
int ret = ESPCONN_OK;
struct ip_addr ipaddr;
const char *server_port = NULL;
espconn_msg *pserver = NULL;
pmbedtls_msg mbedTLSMsg = NULL;
if (lwIPThreadFlag == false)
mbedtls_threadinit();
if (plink_server != NULL)
return ESPCONN_INPROGRESS;
lwIP_REQUIRE_ACTION(espconn, exit, ret = ESPCONN_ARG);
/*Creates a new server control message*/
pserver = (espconn_msg *) os_zalloc( sizeof(espconn_msg));
lwIP_REQUIRE_ACTION(espconn, exit, ret = ESPCONN_MEM);
mbedTLSMsg = mbedtls_msg_new();
lwIP_REQUIRE_ACTION(mbedTLSMsg, exit, ret = ESPCONN_MEM);
server_port = (const char *)sys_itoa(espconn->proto.tcp->local_port);
/*start the connection*/
ret = mbedtls_net_bind(&mbedTLSMsg->listen_fd, NULL, server_port, MBEDTLS_NET_PROTO_TCP);
lwIP_REQUIRE_NOERROR_ACTION(ret, exit, ret = ESPCONN_MEM);
espconn->state = ESPCONN_LISTEN;
pserver->pespconn = NULL;
pserver->pssl = mbedTLSMsg;
pserver->preverse = espconn;
pserver->count_opt = MEMP_NUM_TCP_PCB;
pserver->pcommon.timeout = 0x0a;
espconn->state = ESPCONN_LISTEN;
plink_server = pserver;
exit:
if (ret != ESPCONN_OK) {
if (mbedTLSMsg != NULL)
mbedtls_msg_free(&mbedTLSMsg);
if (pserver != NULL)
os_free(pserver);
}
return ret;
}
/******************************************************************************
* FunctionName : espconn_ssl_delete
* Description : delete the server: delete a listening PCB and free it
* Parameters : pdeletecon -- the espconn used to delete a server
* Returns : none
*******************************************************************************/
sint8 espconn_ssl_delete(struct espconn *pdeletecon)
{
remot_info *pinfo = NULL;
espconn_msg *pdelete_msg = NULL;
pmbedtls_msg mbedTLSMsg = NULL;
if (pdeletecon == NULL)
return ESPCONN_ARG;
espconn_get_connection_info(pdeletecon, &pinfo, ESPCONN_SSL);
/*make sure all the active connection have been disconnect*/
if (pdeletecon->link_cnt != 0)
return ESPCONN_INPROGRESS;
else {
pdelete_msg = plink_server;
if (pdelete_msg != NULL && pdelete_msg->preverse == pdeletecon) {
mbedTLSMsg = pdelete_msg->pssl;
espconn_kill_pcb(pdeletecon->proto.tcp->local_port);
mbedtls_net_free(&mbedTLSMsg->listen_fd);
mbedtls_msg_free(&mbedTLSMsg);
pdelete_msg->pssl = mbedTLSMsg;
os_free(pdelete_msg);
pdelete_msg = NULL;
plink_server = pdelete_msg;
mbedtls_parame_free(&def_private_key);
mbedtls_parame_free(&def_certificate);
return ESPCONN_OK;
} else {
return ESPCONN_ARG;
}
}
}
/******************************************************************************
* FunctionName : espconn_ssl_write
* Description : sent data for client or server
* Parameters : void *arg -- client or server to send
* uint8* psent -- Data to send
* uint16 length -- Length of data to send
* Returns : none
*******************************************************************************/
void espconn_ssl_sent(void *arg, uint8 *psent, uint16 length)
{
espconn_msg *Threadmsg = arg;
uint16 out_msglen = length;
int ret = ESPCONN_OK;
lwIP_ASSERT(Threadmsg);
lwIP_ASSERT(psent);
lwIP_ASSERT(length);
pmbedtls_msg mbedTLSMsg = Threadmsg->pssl;
lwIP_ASSERT(mbedTLSMsg);
if (length > MBEDTLS_SSL_PLAIN_ADD){
out_msglen = MBEDTLS_SSL_PLAIN_ADD;
}
Threadmsg->pcommon.write_flag = true;
ret = mbedtls_ssl_write(&mbedTLSMsg->ssl, psent, out_msglen);
if (ret > 0){
Threadmsg->pcommon.ptrbuf = psent + ret;
Threadmsg->pcommon.cntr = length - ret;
} else{
if (ret == MBEDTLS_ERR_SSL_WANT_WRITE || ret == 0) {
} else{
mbedtls_fail_info(Threadmsg, ret);
ets_post(lwIPThreadPrio, NETCONN_EVENT_CLOSE,(uint32)Threadmsg);
}
}
}
/******************************************************************************
* FunctionName : espconn_ssl_disconnect
* Description : A new incoming connection has been disconnected.
* Parameters : espconn -- the espconn used to disconnect with host
* Returns : none
*******************************************************************************/
void espconn_ssl_disconnect(espconn_msg *Threadmsg)
{
lwIP_ASSERT(Threadmsg);
pmbedtls_msg mbedTLSMsg = Threadmsg->pssl;
lwIP_ASSERT(mbedTLSMsg);
mbedtls_net_free(&mbedTLSMsg->fd);
Threadmsg->pespconn->state = ESPCONN_CLOSE;
ets_post(lwIPThreadPrio, NETCONN_EVENT_CLOSE, (uint32)Threadmsg);
}
/*
* Checkup routine
*/
int mbedtls_x509_test(int verbose, char *ca_crt, size_t ca_crt_len, char *cli_crt, size_t cli_crt_len)
{
#if defined(MBEDTLS_SHA1_C)
int ret;
uint32_t flags;
mbedtls_x509_crt cacert;
mbedtls_x509_crt clicert;
if( verbose != 0 )
os_printf( " X.509 certificate load: " );
mbedtls_x509_crt_init( &clicert );
ret = mbedtls_x509_crt_parse( &clicert, (const unsigned char *) cli_crt,
cli_crt_len );
if( ret != 0 )
{
if( verbose != 0 )
os_printf( "failed\n" );
return( ret );
}
mbedtls_x509_crt_init( &cacert );
ret = mbedtls_x509_crt_parse( &cacert, (const unsigned char *) ca_crt,
ca_crt_len );
if( ret != 0 )
{
if( verbose != 0 )
os_printf( "failed\n" );
return( ret );
}
if( verbose != 0 )
os_printf( "passed\n X.509 signature verify: ");
ret = mbedtls_x509_crt_verify( &clicert, &cacert, NULL, NULL, &flags, NULL, NULL );
if( ret != 0 )
{
if( verbose != 0 )
os_printf( "failed\n" );
return( ret );
}
if( verbose != 0 )
os_printf( "passed\n\n");
mbedtls_x509_crt_free( &cacert );
mbedtls_x509_crt_free( &clicert );
return( 0 );
#else
((void) verbose);
return( 0 );
#endif /* MBEDTLS_CERTS_C && MBEDTLS_SHA1_C */
}
#endif
/*
* ESPRSSIF MIT License
*
* Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
* it is free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "lwip/netif.h"
#include "lwip/inet.h"
#include "netif/etharp.h"
#include "lwip/tcp.h"
#include "lwip/ip.h"
#include "lwip/init.h"
#include "ets_sys.h"
#include "os_type.h"
#ifdef MEMLEAK_DEBUG
static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;
#endif
#if !defined(ESPCONN_MBEDTLS)
#include "sys/espconn_mbedtls.h"
ssl_opt ssl_option = {
{NULL, ESPCONN_SECURE_DEFAULT_SIZE, 0, false, 0, false},
{NULL, ESPCONN_SECURE_DEFAULT_SIZE, 0, false, 0, false},
0
};
unsigned int max_content_len = ESPCONN_SECURE_DEFAULT_SIZE;
/******************************************************************************
* FunctionName : espconn_encry_connect
* Description : The function given as the connect
* Parameters : espconn -- the espconn used to listen the connection
* Returns : none
*******************************************************************************/
sint8 ICACHE_FLASH_ATTR
espconn_secure_connect(struct espconn *espconn)
{
struct ip_addr ipaddr;
struct ip_info ipinfo;
uint8 connect_status = 0;
uint16 current_size = 0;
if (espconn == NULL || espconn ->type != ESPCONN_TCP)
return ESPCONN_ARG;
if (wifi_get_opmode() == ESPCONN_STA){
wifi_get_ip_info(STA_NETIF, &ipinfo);
if (ipinfo.ip.addr == 0) {
return ESPCONN_RTE;
}
} else if (wifi_get_opmode() == ESPCONN_AP) {
wifi_get_ip_info(AP_NETIF, &ipinfo);
if (ipinfo.ip.addr == 0) {
return ESPCONN_RTE;
}
} else if (wifi_get_opmode() == ESPCONN_AP_STA) {
IP4_ADDR(&ipaddr, espconn->proto.tcp->remote_ip[0],
espconn->proto.tcp->remote_ip[1],
espconn->proto.tcp->remote_ip[2],
espconn->proto.tcp->remote_ip[3]);
ipaddr.addr <<= 8;
wifi_get_ip_info(AP_NETIF, &ipinfo);
ipinfo.ip.addr <<= 8;
espconn_printf("softap_addr = %x, remote_addr = %x\n", ipinfo.ip.addr, ipaddr.addr);
if (ipaddr.addr != ipinfo.ip.addr) {
connect_status = wifi_station_get_connect_status();
if (connect_status == STATION_GOT_IP) {
wifi_get_ip_info(STA_NETIF, &ipinfo);
if (ipinfo.ip.addr == 0)
return ESPCONN_RTE;
} else if (connect_status == STATION_IDLE) {
return ESPCONN_RTE;
} else {
return connect_status;
}
}
}
current_size = espconn_secure_get_size(ESPCONN_CLIENT);
current_size += ESPCONN_SECURE_DEFAULT_HEAP;
// ssl_printf("heap_size %d %d\n", system_get_free_heap_size(), current_size);
if (system_get_free_heap_size() <= current_size)
return ESPCONN_MEM;
return espconn_ssl_client(espconn);
}
/******************************************************************************
* FunctionName : espconn_encry_disconnect
* Description : The function given as the disconnect
* Parameters : espconn -- the espconn used to listen the connection
* Returns : none
*******************************************************************************/
sint8 ICACHE_FLASH_ATTR
espconn_secure_disconnect(struct espconn *espconn)
{
espconn_msg *pnode = NULL;
bool value = false;
if (espconn == NULL)
return ESPCONN_ARG;
value = espconn_find_connection(espconn, &pnode);
if (value){
if (pnode->pespconn->state == ESPCONN_CLOSE)
return ESPCONN_INPROGRESS;
espconn_ssl_disconnect(pnode);
return ESPCONN_OK;
}
else
return ESPCONN_ARG;
}
/******************************************************************************
* FunctionName : espconn_encry_sent
* Description : sent data for client or server
* Parameters : espconn -- espconn to set for client or server
* psent -- data to send
* length -- length of data to send
* Returns : none
*******************************************************************************/
sint8 ICACHE_FLASH_ATTR
espconn_secure_sent(struct espconn *espconn, uint8 *psent, uint16 length)
{
espconn_msg *pnode = NULL;
bool value = false;
if (espconn == NULL)
return ESPCONN_ARG;
espconn ->state = ESPCONN_WRITE;
value = espconn_find_connection(espconn, &pnode);
if (value){
pmbedtls_msg pssl = NULL;
pssl = pnode->pssl;
if (pssl->SentFnFlag){
pssl->SentFnFlag = false;
espconn_ssl_sent(pnode, psent, length);
return ESPCONN_OK;
}else
return ESPCONN_INPROGRESS;
}
else
return ESPCONN_ARG;
}
/******************************************************************************
* FunctionName : espconn_secure_send
* Description : send data for client or server
* Parameters : espconn -- espconn to set for client or server
* psent -- data to send
* length -- length of data to send
* Returns : none
*******************************************************************************/
sint8 espconn_secure_send(struct espconn *espconn, uint8 *psent, uint16 length) __attribute__((alias("espconn_secure_sent")));
sint8 ICACHE_FLASH_ATTR
espconn_secure_accept(struct espconn *espconn)
{
if (espconn == NULL || espconn ->type != ESPCONN_TCP)
return ESPCONN_ARG;
return espconn_ssl_server(espconn);
}
/******************************************************************************
* FunctionName : espconn_secure_set_size
* Description : set the buffer size for client or server
* Parameters : level -- set for client or server
* 1: client,2:server,3:client and server
* size -- buffer size
* Returns : true or false
*******************************************************************************/
bool ICACHE_FLASH_ATTR espconn_secure_set_size(uint8 level, uint16 size)
{
size = (size < 4096) ? 4096 : size;
if (level >= ESPCONN_MAX || level <= ESPCONN_IDLE)
return false;
if (size > ESPCONN_SECURE_MAX_SIZE || size < ESPCONN_SECURE_DEFAULT_SIZE)
return false;
max_content_len = size;
return true;
}
/******************************************************************************
* FunctionName : espconn_secure_get_size
* Description : get buffer size for client or server
* Parameters : level -- set for client or server
* 1: client,2:server,3:client and server
* Returns : buffer size for client or server
*******************************************************************************/
sint16 ICACHE_FLASH_ATTR espconn_secure_get_size(uint8 level)
{
if (level >= ESPCONN_MAX || level <= ESPCONN_IDLE)
return ESPCONN_ARG;
return max_content_len;
}
/******************************************************************************
* FunctionName : espconn_secure_ca_enable
* Description : enable the certificate authenticate and set the flash sector
* as client or server
* Parameters : level -- set for client or server
* 1: client,2:server,3:client and server
* flash_sector -- flash sector for save certificate
* Returns : result true or false
*******************************************************************************/
bool ICACHE_FLASH_ATTR espconn_secure_ca_enable(uint8 level, uint32 flash_sector )
{
if (level >= ESPCONN_MAX || level <= ESPCONN_IDLE || flash_sector <= 0)
return false;
if (level == ESPCONN_CLIENT){
ssl_option.client.cert_ca_sector.sector = flash_sector;
ssl_option.client.cert_ca_sector.flag = true;
}
if (level == ESPCONN_SERVER){
ssl_option.server.cert_ca_sector.sector = flash_sector;
ssl_option.server.cert_ca_sector.flag = true;
}
if (level == ESPCONN_BOTH) {
ssl_option.client.cert_ca_sector.sector = flash_sector;
ssl_option.server.cert_ca_sector.sector = flash_sector;
ssl_option.client.cert_ca_sector.flag = true;
ssl_option.server.cert_ca_sector.flag = true;
}
return true;
}
/******************************************************************************
* FunctionName : espconn_secure_ca_disable
* Description : disable the certificate authenticate as client or server
* Parameters : level -- set for client or server
* 1: client,2:server,3:client and server
* Returns : result true or false
*******************************************************************************/
bool ICACHE_FLASH_ATTR espconn_secure_ca_disable(uint8 level)
{
if (level >= ESPCONN_MAX || level <= ESPCONN_IDLE)
return false;
if (level == ESPCONN_CLIENT)
ssl_option.client.cert_ca_sector.flag = false;
if (level == ESPCONN_SERVER)
ssl_option.server.cert_ca_sector.flag = false;
if (level == ESPCONN_BOTH) {
ssl_option.client.cert_ca_sector.flag = false;
ssl_option.server.cert_ca_sector.flag = false;
}
return true;
}
/******************************************************************************
* FunctionName : espconn_secure_cert_req_enable
* Description : enable the client certificate authenticate and set the flash sector
* as client or server
* Parameters : level -- set for client or server
* 1: client,2:server,3:client and server
* flash_sector -- flash sector for save certificate
* Returns : result true or false
*******************************************************************************/
bool ICACHE_FLASH_ATTR espconn_secure_cert_req_enable(uint8 level, uint32 flash_sector )
{
if (level >= ESPCONN_MAX || level <= ESPCONN_IDLE || flash_sector <= 0)
return false;
if (level == ESPCONN_CLIENT){
ssl_option.client.cert_req_sector.sector = flash_sector;
ssl_option.client.cert_req_sector.flag = true;
}
if (level == ESPCONN_SERVER){
ssl_option.server.cert_req_sector.sector = flash_sector;
ssl_option.server.cert_req_sector.flag = true;
}
if (level == ESPCONN_BOTH) {
ssl_option.client.cert_req_sector.sector = flash_sector;
ssl_option.server.cert_req_sector.sector = flash_sector;
ssl_option.client.cert_req_sector.flag = true;
ssl_option.server.cert_req_sector.flag = true;
}
return true;
}
/******************************************************************************
* FunctionName : espconn_secure_ca_disable
* Description : disable the client certificate authenticate as client or server
* Parameters : level -- set for client or server
* 1: client,2:server,3:client and server
* Returns : result true or false
*******************************************************************************/
bool ICACHE_FLASH_ATTR espconn_secure_cert_req_disable(uint8 level)
{
if (level >= ESPCONN_MAX || level <= ESPCONN_IDLE)
return false;
if (level == ESPCONN_CLIENT)
ssl_option.client.cert_req_sector.flag = false;
if (level == ESPCONN_SERVER)
ssl_option.server.cert_req_sector.flag = false;
if (level == ESPCONN_BOTH) {
ssl_option.client.cert_req_sector.flag = false;
ssl_option.server.cert_req_sector.flag = false;
}
return true;
}
/******************************************************************************
* FunctionName : espconn_secure_set_default_certificate
* Description : Load the certificates in memory depending on compile-time
* and user options.
* Parameters : certificate -- Load the certificate
* length -- Load the certificate length
* Returns : result true or false
*******************************************************************************/
bool ICACHE_FLASH_ATTR espconn_secure_set_default_certificate(const uint8* certificate, uint16 length)
{
if (certificate == NULL || length > ESPCONN_SECURE_MAX_SIZE)
return false;
return mbedtls_load_default_obj(0, ESPCONN_CERT_OWN, certificate, length);
}
/******************************************************************************
* FunctionName : espconn_secure_set_default_private_key
* Description : Load the key in memory depending on compile-time
* and user options.
* Parameters : private_key -- Load the key
* length -- Load the key length
* Returns : result true or false
*******************************************************************************/
bool ICACHE_FLASH_ATTR espconn_secure_set_default_private_key(const uint8* private_key, uint16 length)
{
if (private_key == NULL || length > ESPCONN_SECURE_MAX_SIZE)
return false;
return mbedtls_load_default_obj(0, ESPCONN_PK, private_key, length);
}
/******************************************************************************
* FunctionName : espconn_secure_delete
* Description : delete the secure server host
* Parameters : espconn -- espconn to set for client or server
* Returns : result
*******************************************************************************/
sint8 ICACHE_FLASH_ATTR espconn_secure_delete(struct espconn *espconn)
{
sint8 error = ESPCONN_OK;
error = espconn_ssl_delete(espconn);
return error;
}
bool espconn_secure_obj_load(int obj_type, uint32 flash_sector, uint16 length)
{
if (length > ESPCONN_SECURE_MAX_SIZE || length == 0)
return false;
if (obj_type != ESPCONN_PK && obj_type != ESPCONN_CERT_OWN)
return false;
return mbedtls_load_default_obj(flash_sector, obj_type, NULL, length);
}
#endif
/*
* ESPRSSIF MIT License
*
* Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
* it is free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "lwip/memp.h"
#include "lwip/def.h"
#include "ets_sys.h"
#include "os_type.h"
#include "sys/ringbuf.h"
#include "sys/socket.h"
#ifdef MEMLEAK_DEBUG
static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;
#endif
ringbuf_t ringbuf_new(size_t capacity)
{
ringbuf_t rb = (ringbuf_t)os_zalloc(sizeof(struct ringbuf_t));
if (rb){
rb->size = capacity + 1;
rb->buf = (uint8*)os_zalloc(rb->size);
if (rb->buf){
ringbuf_reset(rb);
}else{
os_free(rb);
return NULL;
}
}
return rb;
}
size_t ringbuf_buffer_size(const struct ringbuf_t *rb)
{
return rb->size;
}
void ringbuf_reset(ringbuf_t rb)
{
rb ->head = rb->tail = rb->buf;
}
void ringbuf_free(ringbuf_t *rb)
{
lwIP_ASSERT(rb && *rb);
os_free((*rb)->buf);
os_free(*rb);
*rb = NULL;
}
size_t ringbuf_capacity(const struct ringbuf_t *rb)
{
return ringbuf_buffer_size(rb) - 1;
}
static const uint8_t* ringbuf_end(const struct ringbuf_t *rb)
{
return rb->buf + ringbuf_buffer_size(rb);
}
size_t ringbuf_bytes_free(const struct ringbuf_t *rb)
{
if (rb->head >= rb->tail){
return ringbuf_capacity(rb) - (rb->head - rb->tail);
}else{
return rb->tail - rb->head -1;
}
}
size_t ringbuf_bytes_used(const struct ringbuf_t *rb)
{
return ringbuf_capacity(rb) - ringbuf_bytes_free(rb);
}
int ringbuf_is_full(const struct ringbuf_t *rb)
{
return ringbuf_bytes_free(rb) == 0;
}
int ringbuf_is_empty(const struct ringbuf_t *rb)
{
return ringbuf_bytes_free(rb) == ringbuf_capacity(rb);
}
const void* ringbuf_tail(const struct ringbuf_t *rb)
{
return rb->tail;
}
const void* ringbuf_head(const struct ringbuf_t *rb)
{
return rb->head;
}
static uint8_t *ringbuf_nextp(ringbuf_t rb, const uint8_t *p)
{
lwIP_ASSERT((p >= rb->buf) && (p < ringbuf_end(rb)));
return rb->buf + ((++p -rb->buf) % ringbuf_buffer_size(rb));
}
size_t ringbuf_findchr(const struct ringbuf_t *rb, int c, size_t offset)
{
const uint8_t *bufend = ringbuf_end(rb);
size_t bytes_used = ringbuf_bytes_used(rb);
if (offset >= bytes_used)
return bytes_used;
const uint8_t *start = rb ->buf + (((rb->tail - rb->buf) + offset) % ringbuf_buffer_size(rb));
lwIP_ASSERT(bufend > start);
size_t n = LWIP_MIN(bufend - start, bytes_used - offset);
const uint8_t *found = (const uint8_t *)memchr(start, c, n);
if (found)
return offset + (found - start);
else
return ringbuf_findchr(rb, c, offset + n);
}
size_t ringbuf_memset(ringbuf_t dst, int c, size_t len)
{
const uint8_t *bufend = ringbuf_end(dst);
size_t nwritten = 0;
size_t count = LWIP_MIN(len, ringbuf_buffer_size(dst));
int overflow = count > ringbuf_bytes_free(dst);
while (nwritten != count){
lwIP_ASSERT(bufend > dst->head);
size_t n = LWIP_MIN(bufend - dst->head, count - nwritten);
os_memset(dst->head, c, n);
dst->head += n;
nwritten += n;
if (dst->head == bufend)
dst->head = dst->buf;
}
if (overflow){
dst->tail = ringbuf_nextp(dst, dst->head);
lwIP_ASSERT(ringbuf_is_full(dst));
}
return nwritten;
}
void *ringbuf_memcpy_into(ringbuf_t dst,const void *src, size_t count)
{
const uint8_t *u8src = src;
const uint8_t *bufend = ringbuf_end(dst);
int overflow = count > ringbuf_bytes_free(dst);
size_t nread = 0;
while (nread != count){
lwIP_ASSERT(bufend > dst->head);
size_t n = LWIP_MIN(bufend - dst->head, count - nread);
os_memcpy(dst->head, u8src + nread, n);
dst->head += n;
nread += n;
if (dst->head == bufend)
dst->head = dst->buf;
}
if (overflow) {
dst->tail = ringbuf_nextp(dst, dst->head);
lwIP_ASSERT(ringbuf_is_full(dst));
}
return dst->head;
}
void *ringbuf_memcpy_from(void *dst,ringbuf_t src, size_t count)
{
size_t bytes_used = ringbuf_bytes_used(src);
if (count > bytes_used)
return NULL;
const uint8_t *u8dst = dst;
const uint8_t *bufend = ringbuf_end(src);
size_t nwritten = 0;
while (nwritten != count){
lwIP_ASSERT(bufend > src->tail);
size_t n = LWIP_MIN(bufend - src->tail, count - nwritten);
os_memcpy((uint8_t*)u8dst + nwritten, src->tail, n);
src->tail += n;
nwritten += n;
if (src->tail == bufend)
src->tail = src->buf;
}
lwIP_ASSERT(count + ringbuf_bytes_used(src) == bytes_used);
return src->tail;
}
/*
* ESPRSSIF MIT License
*
* Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
* it is free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "c_types.h"
#include <stdio.h>
//#include "os.h"
#include <fcntl.h>
#ifdef MEMLEAK_DEBUG
static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;
#endif
int ICACHE_FLASH_ATTR __attribute__((weak))
_open_r(struct _reent *r, const char *filename, int flags, int mode)
{
return 0;
}
_ssize_t ICACHE_FLASH_ATTR __attribute__((weak))
_read_r(struct _reent *r, int fd, void *buf, size_t cnt)
{
return -1;
}
_ssize_t ICACHE_FLASH_ATTR __attribute__((weak))
_write_r(struct _reent *r, int fd, void *buf, size_t cnt)
{
return -1;
}
_off_t ICACHE_FLASH_ATTR __attribute__((weak))
_lseek_r(struct _reent *r, int fd, _off_t pos, int whence)
{
return -1;
}
int ICACHE_FLASH_ATTR __attribute__((weak))
_close_r(struct _reent *r, int fd)
{
return -1;
}
int ICACHE_FLASH_ATTR __attribute__((weak))
_rename_r(struct _reent *r, const char *from, const char *to)
{
return 0;
}
int ICACHE_FLASH_ATTR __attribute__((weak))
_unlink_r(struct _reent *r, const char *filename)
{
return 0;
}
int ICACHE_FLASH_ATTR __attribute__((weak))
_fstat_r(struct _reent *r, int fd, struct stat *s)
{
return 0;
}
void *ICACHE_FLASH_ATTR __attribute__((weak))
_sbrk_r(void *ptr, int incr)
{
return 0;
}
char *sys_reverse(char *s)
{
char temp = 0;
char *p = s;
char *q = s;
while(*q)
++q;
q--;
while(q > p){
temp = *p;
*p++ = *q;
*q-- = temp;
}
return s;
}
char *sys_itoa(int n)
{
int i = 0, Negative = 0;
static char s[32];
Negative = n;
if (Negative < 0){
n = -n;
}
do {
s[i++] = n%10 + '0';
n = n / 10;
}while(n > 0);
if (Negative < 0){
s[i++] = '-';
}
s[i] = '\0';
return sys_reverse(s);
}
/*
* ESPRSSIF MIT License
*
* Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
* it is free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "lwip/netif.h"
#include "lwip/inet.h"
#include "netif/etharp.h"
#include "lwip/tcp.h"
#include "lwip/ip.h"
#include "lwip/init.h"
#include "lwip/tcp_impl.h"
#include "lwip/memp.h"
#include "ets_sys.h"
#include "os_type.h"
#include "lwip/mem.h"
#include "sys/socket.h"
#ifdef MEMLEAK_DEBUG
static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;
#endif
/** The global array of available sockets */
static lwIP_sock sockets[NUM_SOCKETS];
/** Table to quickly map an lwIP error (err_t) to a socket error
* by using -err as an index */
static const int err_to_errno_table[] =
{
0, /* ERR_OK 0 No error, everything OK. */
// ENOMEM, /* ERR_MEM -1 Out of memory error. */
// ENOBUFS, /* ERR_BUF -2 Buffer error. */
// EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */
// EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */
// EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */
// EINVAL, /* ERR_VAL -6 Illegal value. */
// EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */
// ECONNABORTED, /* ERR_ABRT -8 Connection aborted. */
// ECONNRESET, /* ERR_RST -9 Connection reset. */
// ESHUTDOWN, /* ERR_CLSD -10 Connection closed. */
// ENOTCONN, /* ERR_CONN -11 Not connected. */
// EIO, /* ERR_ARG -12 Illegal argument. */
// EADDRINUSE, /* ERR_USE -13 Address in use. */
-1, /* ERR_IF -14 Low-level netif error */
-1, /* ERR_ISCONN -15 Already connected. */
};
#define ERR_TO_ERRNO_TABLE_SIZE \
(sizeof(err_to_errno_table)/sizeof(err_to_errno_table[0]))
#define err_to_errno(err) \
((unsigned)(-(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \
err_to_errno_table[-(err)] : EIO)
#ifdef ERRNO
#ifndef set_errno
#define set_errno(err) errno = (err)
#endif
#else /* ERRNO */
#define set_errno(err)
#endif /* ERRNO */
#define sock_set_errno(sk, e) do { \
sk->err = (e); \
set_errno(sk->err); \
} while (0)
static lwIP_sock *get_socket(int s);
static int find_socket(lwIP_netconn *newconn)
{
int i = 0;
lwIP_ASSERT(newconn);
for (i = 0; i < NUM_SOCKETS; ++i)
{
if (sockets[i].conn && sockets[i].conn == newconn)
return i;
}
return -1;
}
static void remove_tcp(lwIP_netconn *conn)
{
struct tcp_pcb *pcb = NULL;
sint8 ret = ERR_OK;
lwIP_REQUIRE_ACTION(conn, exit, ret = ERR_ARG);
lwIP_REQUIRE_ACTION(conn->tcp, exit, ret = ERR_ARG);
pcb = conn->tcp;
tcp_arg(pcb, NULL);
tcp_recv(pcb, NULL);
tcp_sent(pcb, NULL);
tcp_poll(pcb, NULL, 0);
tcp_err(pcb, NULL);
exit:
return;
}
static void free_netconn(lwIP_netconn *netconn)
{
lwIP_ASSERT(netconn);
if (netconn->readbuf)
{
ringbuf_free(&netconn->readbuf);
}
os_free(netconn);
netconn = NULL;
}
static lwIP_netconn *
netconn_alloc(netconn_type type, void *arg)
{
sint8 ret = ERR_OK;
lwIP_netconn *netconn = NULL;
struct tcp_pcb *pcb = arg;
lwIP_REQUIRE_ACTION(pcb, exit, ret = ERR_ARG);
netconn = (lwIP_netconn *)os_zalloc(sizeof(lwIP_netconn));
lwIP_REQUIRE_ACTION(netconn, exit, ret = ERR_MEM);
netconn->readbuf = ringbuf_new(TCP_SND_BUF);
lwIP_REQUIRE_ACTION(netconn->readbuf, exit, ret = ERR_MEM);
system_overclock();
netconn->socket = -1;
exit:
if (ret != ERR_OK)
{
free_netconn(netconn);
}
return netconn;
}
static err_t netconn_getaddr(lwIP_netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local)
{
sint8 ret = ERR_OK;
lwIP_REQUIRE_ACTION(conn, exit, ret = ERR_ARG);
lwIP_REQUIRE_ACTION(addr, exit, ret = ERR_ARG);
lwIP_REQUIRE_ACTION(port, exit, ret = ERR_ARG);
lwIP_REQUIRE_ACTION(conn->tcp, exit, ret = ERR_ARG);
*port = local==1 ? conn->tcp->local_port : conn->tcp->remote_port;
*addr = local==1 ? conn->tcp->local_ip : conn->tcp->remote_ip;
exit:
return ret;
}
/** Free a socket. The socket's netconn must have been
* delete before!
*
* @param sock the socket to free
* @param is_tcp != 0 for TCP sockets, used to free lastdata
*/
static void free_socket(lwIP_sock *sock)
{
void *lastdata = NULL;
sock->conn = NULL;
sock->recv_data_len = 0;
sock->recv_index = 0;
sock->send_buffer = NULL;
sock->send_index = 0;
}
static err_t recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
lwIP_netconn *newconn = arg;
err = ESP_OK;
lwIP_REQUIRE_ACTION(newconn, exit, err = ESP_ARG);
if (p!= NULL)
{
struct pbuf *pthis = NULL;
if (newconn->readbuf != NULL)
{
for (pthis = p; pthis != NULL; pthis = pthis->next)
{
newconn->state = NETCONN_STATE_READ;
ringbuf_memcpy_into(newconn->readbuf, pthis->payload, pthis->len);
tcp_recved(newconn->tcp, pthis->len);
newconn->state = NETCONN_STATE_ESTABLISHED;
lwIP_EVENT_PARSE(find_socket(newconn), ERR_OK);
}
pbuf_free(p);
}
else
{
tcp_recved(newconn->tcp, p->tot_len);
pbuf_free(p);
err = ERR_MEM;
}
}
else
{
lwIP_EVENT_PARSE(find_socket(newconn), NETCONN_EVENT_CLOSE);
}
exit:
return err;
}
static err_t poll_tcp(void *arg, struct tcp_pcb *pcb)
{
lwIP_netconn *conn = arg;
lwIP_ASSERT(conn);
return ERR_OK;
}
static err_t sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
{
lwIP_netconn *conn = arg;
lwIP_ASSERT(conn);
conn->state = NETCONN_STATE_ESTABLISHED;
lwIP_EVENT_THREAD(find_socket(conn), NETCONN_EVENT_SEND, len);
return ERR_OK;
}
static void err_tcp(void *arg, err_t err)
{
lwIP_netconn *conn = arg;
lwIP_ASSERT(conn);
conn->state = NETCONN_STATE_ERROR;
ESP_LOG("%s %d %p\n",__FILE__, __LINE__, conn->tcp);
switch (conn->tcp->state)
{
case SYN_SENT:
if (conn->tcp->nrtx == TCP_SYNMAXRTX)
{
err = ERR_CONN;
}
break;
case ESTABLISHED:
if (conn->tcp->nrtx == TCP_MAXRTX)
{
err = ERR_TIMEOUT;
}
break;
default:
break;
}
lwIP_EVENT_PARSE(find_socket(conn), err);
return;
}
/**
* TCP callback function if a connection (opened by tcp_connect/do_connect) has
* been established (or reset by the remote host).
*
* @see tcp.h (struct tcp_pcb.connected) for parameters and return values
*/
static err_t do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
{
lwIP_netconn *conn = arg;
err = ERR_OK;
lwIP_REQUIRE_ACTION(conn, exit, err = ESP_ARG);
conn->state = NETCONN_STATE_ESTABLISHED;
conn->readbuf = ringbuf_new(TCP_SND_BUF);
lwIP_REQUIRE_ACTION(conn->readbuf, exit, err = ESP_MEM);
lwIP_EVENT_PARSE(find_socket(conn), ERR_OK);
exit:
return err;
}
static void setup_tcp(lwIP_netconn *conn)
{
struct tcp_pcb *pcb = NULL;
sint8 ret = ERR_OK;
lwIP_REQUIRE_ACTION(conn, exit, ret = ERR_ARG);
lwIP_REQUIRE_ACTION(conn->tcp, exit, ret = ERR_ARG);
pcb = conn->tcp;
tcp_arg(pcb, conn);
tcp_recv(pcb, recv_tcp);
tcp_sent(pcb, sent_tcp);
tcp_poll(pcb, poll_tcp, 4);
tcp_err(pcb, err_tcp);
exit:
return;
}
static err_t do_accepted(void *arg, struct tcp_pcb *newpcb, err_t err)
{
lwIP_netconn *newconn = NULL;
lwIP_netconn *conn = arg;
err = ERR_OK;
lwIP_REQUIRE_ACTION(conn, exit, err = ESP_ARG);
/* We have to set the callback here even though
* the new socket is unknown. conn->socket is marked as -1. */
newconn = netconn_alloc(conn->type, newpcb);
lwIP_REQUIRE_ACTION(conn, exit, err = ERR_MEM);
newconn->tcp = newpcb;
setup_tcp(newconn);
newconn->state = NETCONN_STATE_ESTABLISHED;
conn->acceptmbox = newconn;
lwIP_EVENT_PARSE(find_socket(conn), ERR_OK);
exit:
return err;
}
sint8 netconn_delete(lwIP_netconn *conn)
{
sint8 error = ESP_OK;
lwIP_REQUIRE_ACTION(conn, exit, error = ESP_ARG);
tcp_recv(conn->tcp, NULL);
error = tcp_close(conn->tcp);
if (error != ERR_OK)
{
/* closing failed, try again later */
tcp_recv(conn->tcp, recv_tcp);
}
else
{
/* closing succeeded */
remove_tcp(conn);
}
free_netconn(conn);
exit:
return error;
}
sint8 netconn_bind(lwIP_netconn *conn, ip_addr_t *addr, u16_t port)
{
sint8 error = ESP_OK;
lwIP_REQUIRE_ACTION(conn, exit, error = ESP_ARG);
lwIP_REQUIRE_ACTION(addr, exit, error = ESP_ARG);
lwIP_REQUIRE_ACTION(conn->tcp, exit, error = ESP_ARG);
error = tcp_bind(conn->tcp, addr, port);
exit:
return error;
}
sint8 netconn_connect(lwIP_netconn *conn, ip_addr_t *addr, u16_t port)
{
sint8 error = ESP_OK;
lwIP_REQUIRE_ACTION(conn, exit, error = ESP_ARG);
lwIP_REQUIRE_ACTION(addr, exit, error = ESP_ARG);
lwIP_REQUIRE_ACTION(conn->tcp, exit, error = ESP_ARG);
setup_tcp(conn);
error = tcp_connect(conn->tcp, addr, port, do_connected);
exit:
return error;
}
err_t netconn_accept(lwIP_netconn *conn, lwIP_netconn **new_conn)
{
err_t error = ESP_OK;
lwIP_netconn *newconn = NULL;
lwIP_REQUIRE_ACTION(conn, exit, error = ESP_ARG);
lwIP_REQUIRE_ACTION(new_conn, exit, error = ESP_ARG);
*new_conn = NULL;
newconn = (lwIP_netconn *)conn->acceptmbox;
conn->acceptmbox = NULL;
lwIP_REQUIRE_ACTION(newconn, exit, error = ERR_CLSD);
*new_conn = newconn;
exit:
return error;
}
sint8 netconn_listen(lwIP_netconn *conn)
{
sint8 error = ESP_OK;
struct tcp_pcb *lpcb = NULL;
lwIP_REQUIRE_ACTION(conn, exit, error = ESP_ARG);
lwIP_REQUIRE_ACTION(conn->tcp, exit, error = ESP_ARG);
setup_tcp(conn);
lpcb = conn->tcp;
conn->tcp = tcp_listen(conn->tcp);
if (conn->tcp != NULL)
{
tcp_accept(conn->tcp, do_accepted);
}
else
{
conn->tcp = lpcb;
}
exit:
return error;
}
static int alloc_socket(lwIP_netconn *newconn, int accepted)
{
int i = 0;
lwIP_ASSERT(newconn);
/* allocate a new socket identifier */
for (i = 0; i < NUM_SOCKETS; ++i)
{
/* Protect socket array */
if (!sockets[i].conn)
{
sockets[i].conn = newconn;
return i;
}
}
return -1;
}
static lwIP_sock *get_socket(int s)
{
lwIP_sock *sock = NULL;
if ((s < 0) || (s >= NUM_SOCKETS))
{
return NULL;
}
sock = &sockets[s];
if (!sock->conn)
{
return NULL;
}
return sock;
}
int lwip_socket(int domain, int type, int protocol)
{
lwIP_netconn *conn = NULL;
int i = 0;
switch (type)
{
case SOCK_STREAM:
conn = (lwIP_netconn *)os_zalloc(sizeof(lwIP_netconn));
lwIP_REQUIRE_ACTION(conn, exit, i = ESP_MEM);
conn->tcp = tcp_new();
lwIP_REQUIRE_ACTION(conn->tcp, exit, i = ESP_MEM);
conn->socket = -1;
break;
default:
return -1;
}
i = alloc_socket(conn, 0);
if (i == -1)
{
goto exit;
}
conn->socket = i;
exit:
if (i == -1)
{
if (conn->tcp)
memp_free(MEMP_TCP_PCB,conn->tcp);
if (conn)
os_free(conn);
}
return i;
}
int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
{
lwIP_sock *sock = NULL;
ip_addr_t local_addr;
uint16 local_port = 0;
sint8 err = ERR_OK;
const struct sockaddr_in *name_in = NULL;
sock = get_socket(s);
if (!sock)
{
return -1;
}
/* check size, familiy and alignment of 'name' */
LWIP_ERROR("lwip_bind: invalid address",
((namelen == sizeof(struct sockaddr_in)) && ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)),
return -1;);
name_in = (const struct sockaddr_in *) (void*) name;
inet_addr_to_ipaddr(&local_addr, &name_in->sin_addr);
local_port = name_in->sin_port;
err = netconn_bind(sock->conn, &local_addr, ntohs(local_port));
if (err != ESP_OK)
{
ESP_LOG("%s %d, err=%d\n", __FILE__, __LINE__, err);
return -1;
}
ESP_LOG("%s %d, %d succeeded\n", __FILE__, __LINE__, s);
return ERR_OK;
}
int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
{
lwIP_sock *sock = NULL;
err_t err = ERR_OK;
ip_addr_t remote_addr;
u16_t remote_port = 0;
const struct sockaddr_in *name_in = NULL;
sock = get_socket(s);
if (!sock)
{
return -1;
}
/* check size, familiy and alignment of 'name' */
LWIP_ERROR("lwip_connect: invalid address",
((namelen == sizeof(struct sockaddr_in)) && ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)),
return -1;);
name_in = (const struct sockaddr_in *) (void*) name;
inet_addr_to_ipaddr(&remote_addr, &name_in->sin_addr);
remote_port = name_in->sin_port;
err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));
if (err != ERR_OK)
{
ESP_LOG("lwip_connect(%d) failed, err=%d\n", s, err);
return -1;
}
ESP_LOG("lwip_connect(%d) succeeded\n", s);
return ERR_OK;
}
int lwip_fcntl(int s, int cmd, int val)
{
lwIP_sock *sock = get_socket(s);
int ret = -1;
if (!sock || !sock->conn)
{
return -1;
}
switch (cmd)
{
case F_GETFL:
ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0;
break;
case F_SETFL:
if ((val & ~O_NONBLOCK) == 0)
{
/* only O_NONBLOCK, all other bits are zero */
netconn_set_nonblocking(sock->conn, val & O_NONBLOCK);
ret = 0;
}
break;
default:
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val));
break;
}
return ret;
}
uint32_t lwip_getul(char *str)
{
uint32 ret = 0;
while (isdigit(*str))
{
ret = ret * 10 + *str++ - '0';
}
return ret;
}
int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
{
lwIP_sock *sock = NULL;
err_t err = ERR_OK;
lwIP_netconn *newconn = NULL;
int newsock = -1;
sock = get_socket(s);
if (!sock)
{
return -1;
}
/* wait for a new connection */
err = netconn_accept(sock->conn, &newconn);
lwIP_REQUIRE_NOERROR(err, exit);
newsock = alloc_socket(newconn, 0);
if (newsock == -1)
{
goto exit;
}
newconn->socket = newsock;
exit:
if (newsock == -1)
{
netconn_delete(newconn);
}
return newsock;
}
int lwip_listen(int s, int backlog)
{
lwIP_sock *sock = NULL;
err_t err = ERR_OK;
sock = get_socket(s);
if (!sock)
{
return -1;
}
err = netconn_listen(sock->conn);
if (err != ERR_OK)
{
ESP_LOG("lwip_connect(%d) failed, err=%d\n", s, err);
return -1;
}
ESP_LOG("lwip_connect(%d) succeeded\n", s);
return ERR_OK;
}
int lwip_recvfrom(int s, void *mem, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
{
lwIP_sock *sock = NULL;
size_t bytes_used = 0;
int is_tcp = 0;
lwIP_ASSERT(mem);
sock = get_socket(s);
if (!sock)
{
return -1;
}
if (sock->conn != NULL)
{
if (sock->conn->state == NETCONN_STATE_ESTABLISHED)
{
bytes_used = ringbuf_bytes_used(sock->conn->readbuf);
if (bytes_used != 0)
{
if (len > bytes_used)
{
len = bytes_used;
}
ringbuf_memcpy_from(mem, sock->conn->readbuf, len);
return len;
}
else
{
return 0;
}
}
else
{
return 0;
}
}
else
{
return -1;
}
}
int lwip_read(int s, void *mem, size_t len)
{
return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
}
int lwip_recv(int s, void *mem, size_t len, int flags)
{
return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
}
int lwip_send(int s, const void *data, size_t size, int flags)
{
lwIP_sock *sock = NULL;
size_t bytes_used = 0;
err_t Err = ERR_OK;
lwIP_ASSERT(data);
sock = get_socket(s);
if (!sock)
{
return -1;
}
if (tcp_sndbuf(sock->conn->tcp) < size)
{
bytes_used = tcp_sndbuf(sock->conn->tcp);
} else{
bytes_used = size;
}
if (bytes_used > 2 * sock->conn->tcp->mss)
{
bytes_used = 2 * sock->conn->tcp->mss;
}
do
{
Err = tcp_write(sock->conn->tcp, data, bytes_used, 1);
if (Err == ERR_MEM)
size /= 2;
}
while (Err == ERR_MEM && size > 1);
if (Err == ERR_OK)
{
Err = tcp_output(sock->conn->tcp);
} else{
size = Err;
}
return size;
}
int lwip_close(int s)
{
lwIP_sock *sock = NULL;
int err = 0;
sock = get_socket(s);
if (!sock)
{
return -1;
}
if (sock->conn->state != NETCONN_STATE_ERROR){
tcp_recv(sock->conn->tcp, NULL);
err = tcp_close(sock->conn->tcp);
if (err != ERR_OK)
{
/* closing failed, try again later */
tcp_recv(sock->conn->tcp, recv_tcp);
return -1;
}
}
/* closing succeeded */
remove_tcp(sock->conn);
free_netconn(sock->conn);
free_socket(sock);
return ERR_OK;
}
int lwip_write(int s, const void *data, size_t size)
{
lwIP_sock *sock = NULL;
int is_tcp = 0;
size_t bytes_free = 0;
sock = get_socket(s);
if (!sock)
{
return -1;
}
if (sock->conn != NULL)
{
switch (sock->conn->state)
{
case NETCONN_STATE_ESTABLISHED:
return lwip_send(s, data, size, 0);
default:
return -1;
}
}
else
{
return -1;
}
}
static int
lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)
{
lwIP_sock *sock = NULL;
struct sockaddr_in sin;
ip_addr_t naddr;
lwIP_ASSERT(name);
lwIP_ASSERT(namelen);
sock = get_socket(s);
if (!sock)
{
return -1;
}
os_memset(&sin, 0, sizeof(sin));
sin.sin_len = sizeof(sin);
sin.sin_family = AF_INET;
/* get the IP address and port */
netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local);
sin.sin_port = htons(sin.sin_port);
inet_addr_from_ipaddr(&sin.sin_addr, &naddr);
if (*namelen > sizeof(sin))
{
*namelen = sizeof(sin);
}
MEMCPY(name, &sin, *namelen);
return 0;
}
int lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen)
{
return lwip_getaddrname(s, name, namelen, 0);
}
int lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen)
{
return lwip_getaddrname(s, name, namelen, 1);
}
int lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
{
lwIP_sock *sock = NULL;
err_t err = ERR_OK;
lwIP_REQUIRE_ACTION(optval, exit, err = ESP_ARG);
lwIP_REQUIRE_ACTION(optlen, exit, err = ESP_ARG);
sock = get_socket(s);
lwIP_REQUIRE_ACTION(sock, exit, err = ESP_MEM);
switch (level)
{
/* Level: SOL_SOCKET */
case SOL_SOCKET:
switch (optname)
{
/* The option flags */
case SO_ACCEPTCONN:
case SO_BROADCAST:
case SO_KEEPALIVE:
#if SO_REUSE
case SO_REUSEADDR:
case SO_REUSEPORT:
#endif /* SO_REUSE */
*(int*)optval = sock->conn->tcp->so_options & optname;
break;
case SO_TYPE:
switch (NETCONNTYPE_GROUP(sock->conn->type))
{
case NETCONN_TCP:
*(int*)optval = SOCK_STREAM;
break;
case NETCONN_UDP:
*(int*)optval = SOCK_DGRAM;
break;
default:
*(int*)optval = sock->conn->type;
break;
}
break;
break;
}
break;
/* Level: IPPROTO_IP */
case IPPROTO_IP:
break;
#if LWIP_TCP
/* Level: IPPROTO_TCP */
case IPPROTO_TCP:
if (*optlen < sizeof(int))
{
err = ESP_ARG;
lwIP_REQUIRE_NOERROR(err, exit);
}
/* If this is no TCP socket, ignore any options. */
if (sock->conn->type != NETCONN_TCP)
{
err = ESP_ARG;
lwIP_REQUIRE_NOERROR(err, exit);
}
switch (optname)
{
case TCP_NODELAY:
case TCP_KEEPALIVE:
*(int*)optval = (int)sock->conn->tcp->keep_idle;
break;
#if LWIP_TCP_KEEPALIVE
case TCP_KEEPIDLE:
*(int*)optval = (int)(sock->conn->tcp->keep_idle/1000);
break;
case TCP_KEEPINTVL:
*(int*)optval = (int)(sock->conn->tcp->keep_intvl/1000);
break;
case TCP_KEEPCNT:
*(int*)optval = (int)sock->conn->tcp->keep_cnt;
#endif /* LWIP_TCP_KEEPALIVE */
break;
default:
err = ESP_ARG;
lwIP_REQUIRE_NOERROR(err, exit);
break;
} /* switch (optname) */
break;
#endif /* LWIP_TCP */
default:
err = ESP_ARG;
lwIP_REQUIRE_NOERROR(err, exit);
break;
}
exit:
return err;
}
int lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
{
lwIP_sock *sock = NULL;
err_t err = ERR_OK;
lwIP_REQUIRE_ACTION(optval, exit, err = ESP_ARG);
sock = get_socket(s);
lwIP_REQUIRE_ACTION(sock, exit, err = ESP_MEM);
lwIP_REQUIRE_ACTION(sock->conn, exit, err = ESP_MEM);
lwIP_REQUIRE_ACTION(sock->conn->tcp, exit, err = ESP_MEM);
switch (level)
{
/* Level: SOL_SOCKET */
case SOL_SOCKET:
switch (optname)
{
case SO_KEEPALIVE:
if (optlen < sizeof(int))
{
err = ESP_ARG;
lwIP_REQUIRE_NOERROR(err, exit);
}
if (*(int*)optval)
{
sock->conn->tcp->so_options |= optname;
}
else
{
sock->conn->tcp->so_options &= ~optname;
}
break;
}
break;
/* Level: IPPROTO_IP */
case IPPROTO_IP:
break;
/* Level: IPPROTO_TCP */
case IPPROTO_TCP:
if (optlen < sizeof(int))
{
err = ESP_ARG;
lwIP_REQUIRE_NOERROR(err, exit);
}
/* If this is no TCP socket, ignore any options. */
if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_TCP)
{
err = ESP_ARG;
lwIP_REQUIRE_NOERROR(err, exit);
}
switch (optname)
{
case TCP_KEEPALIVE:
sock->conn->tcp->keep_idle = (u32_t) (*(int*) optval);
break;
#if LWIP_TCP_KEEPALIVE
case TCP_KEEPIDLE:
sock->conn->tcp->keep_idle = 1000 * (u32_t) (*(int*) optval);
break;
case TCP_KEEPINTVL:
sock->conn->tcp->keep_intvl = 1000 * (u32_t) (*(int*) optval);
break;
case TCP_KEEPCNT:
sock->conn->tcp->keep_cnt = (u32_t) (*(int*) optval);
break;
#endif /* LWIP_TCP_KEEPALIVE */
default:
err = ESP_ARG;
lwIP_REQUIRE_NOERROR(err, exit);
break;
}
break;
/* UNDEFINED LEVEL */
default:
err = ESP_ARG;
lwIP_REQUIRE_NOERROR(err, exit);
break;
}
exit:
return err;
}
#############################################################
# Required variables for each makefile
# Discard this section from all parent makefiles
# Expected variables (with automatic defaults):
# CSRCS (all "C" files in the dir)
# SUBDIRS (all subdirs with a Makefile)
# GEN_LIBS - list of libs to be generated ()
# GEN_IMAGES - list of images to be generated ()
# COMPONENTS_xxx - a list of libs/objs in the form
# subdir/lib to be extracted and rolled up into
# a generated lib/image xxx.a ()
#
ifndef PDIR
GEN_LIBS = liblibrary.a
endif
#############################################################
# Configuration i.e. compile options etc.
# Target specific stuff (defines etc.) goes in here!
# Generally values applying to a tree are captured in the
# makefile at its root level - these are then overridden
# for a subtree within the makefile rooted therein
#
#DEFINES +=
#############################################################
# Recursion Magic - Don't touch this!!
#
# Each subtree potentially has an include directory
# corresponding to the common APIs applicable to modules
# rooted at that subtree. Accordingly, the INCLUDE PATH
# of a module can only contain the include directories up
# its parent path, and not its siblings
#
# Required for each makefile to inherit from the parent
#
INCLUDES := $(INCLUDES) -I $(PDIR)include
INCLUDES += -I ./
PDIR := ../$(PDIR)
sinclude $(PDIR)Makefile
/*
* FIPS-197 compliant AES implementation
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed 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.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* The AES block cipher was designed by Vincent Rijmen and Joan Daemen.
*
* http://csrc.nist.gov/encryption/aes/rijndael/Rijndael.pdf
* http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_AES_C)
#include "c_types.h"
#include <string.h>
#include "mbedtls/aes.h"
#if defined(MBEDTLS_PADLOCK_C)
#include "mbedtls/padlock.h"
#endif
#if defined(MBEDTLS_AESNI_C)
#include "mbedtls/aesni.h"
#endif
#if defined(MBEDTLS_SELF_TEST)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST */
#if !defined(MBEDTLS_AES_ALT)
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n ) {
volatile unsigned char *p = v; while( n-- ) *p++ = 0;
}
/*
* 32-bit integer manipulation macros (little endian)
*/
#ifndef GET_UINT32_LE
#define GET_UINT32_LE(n,b,i) \
{ \
(n) = ( (uint32_t) (b)[(i) ] ) \
| ( (uint32_t) (b)[(i) + 1] << 8 ) \
| ( (uint32_t) (b)[(i) + 2] << 16 ) \
| ( (uint32_t) (b)[(i) + 3] << 24 ); \
}
#endif
#ifndef PUT_UINT32_LE
#define PUT_UINT32_LE(n,b,i) \
{ \
(b)[(i) ] = (unsigned char) ( ( (n) ) & 0xFF ); \
(b)[(i) + 1] = (unsigned char) ( ( (n) >> 8 ) & 0xFF ); \
(b)[(i) + 2] = (unsigned char) ( ( (n) >> 16 ) & 0xFF ); \
(b)[(i) + 3] = (unsigned char) ( ( (n) >> 24 ) & 0xFF ); \
}
#endif
#if defined(MBEDTLS_PADLOCK_C) && \
( defined(MBEDTLS_HAVE_X86) || defined(MBEDTLS_PADLOCK_ALIGN16) )
static int aes_padlock_ace = -1;
#endif
#if defined(MBEDTLS_AES_ROM_TABLES)
/*
* Forward S-box
*/
static const unsigned char FSb[256] ICACHE_RODATA_ATTR STORE_ATTR =
{
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5,
0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0,
0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC,
0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A,
0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0,
0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B,
0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85,
0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5,
0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17,
0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88,
0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C,
0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9,
0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6,
0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E,
0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94,
0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68,
0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
};
/*
* Forward tables
*/
#define FT \
\
V(A5,63,63,C6), V(84,7C,7C,F8), V(99,77,77,EE), V(8D,7B,7B,F6), \
V(0D,F2,F2,FF), V(BD,6B,6B,D6), V(B1,6F,6F,DE), V(54,C5,C5,91), \
V(50,30,30,60), V(03,01,01,02), V(A9,67,67,CE), V(7D,2B,2B,56), \
V(19,FE,FE,E7), V(62,D7,D7,B5), V(E6,AB,AB,4D), V(9A,76,76,EC), \
V(45,CA,CA,8F), V(9D,82,82,1F), V(40,C9,C9,89), V(87,7D,7D,FA), \
V(15,FA,FA,EF), V(EB,59,59,B2), V(C9,47,47,8E), V(0B,F0,F0,FB), \
V(EC,AD,AD,41), V(67,D4,D4,B3), V(FD,A2,A2,5F), V(EA,AF,AF,45), \
V(BF,9C,9C,23), V(F7,A4,A4,53), V(96,72,72,E4), V(5B,C0,C0,9B), \
V(C2,B7,B7,75), V(1C,FD,FD,E1), V(AE,93,93,3D), V(6A,26,26,4C), \
V(5A,36,36,6C), V(41,3F,3F,7E), V(02,F7,F7,F5), V(4F,CC,CC,83), \
V(5C,34,34,68), V(F4,A5,A5,51), V(34,E5,E5,D1), V(08,F1,F1,F9), \
V(93,71,71,E2), V(73,D8,D8,AB), V(53,31,31,62), V(3F,15,15,2A), \
V(0C,04,04,08), V(52,C7,C7,95), V(65,23,23,46), V(5E,C3,C3,9D), \
V(28,18,18,30), V(A1,96,96,37), V(0F,05,05,0A), V(B5,9A,9A,2F), \
V(09,07,07,0E), V(36,12,12,24), V(9B,80,80,1B), V(3D,E2,E2,DF), \
V(26,EB,EB,CD), V(69,27,27,4E), V(CD,B2,B2,7F), V(9F,75,75,EA), \
V(1B,09,09,12), V(9E,83,83,1D), V(74,2C,2C,58), V(2E,1A,1A,34), \
V(2D,1B,1B,36), V(B2,6E,6E,DC), V(EE,5A,5A,B4), V(FB,A0,A0,5B), \
V(F6,52,52,A4), V(4D,3B,3B,76), V(61,D6,D6,B7), V(CE,B3,B3,7D), \
V(7B,29,29,52), V(3E,E3,E3,DD), V(71,2F,2F,5E), V(97,84,84,13), \
V(F5,53,53,A6), V(68,D1,D1,B9), V(00,00,00,00), V(2C,ED,ED,C1), \
V(60,20,20,40), V(1F,FC,FC,E3), V(C8,B1,B1,79), V(ED,5B,5B,B6), \
V(BE,6A,6A,D4), V(46,CB,CB,8D), V(D9,BE,BE,67), V(4B,39,39,72), \
V(DE,4A,4A,94), V(D4,4C,4C,98), V(E8,58,58,B0), V(4A,CF,CF,85), \
V(6B,D0,D0,BB), V(2A,EF,EF,C5), V(E5,AA,AA,4F), V(16,FB,FB,ED), \
V(C5,43,43,86), V(D7,4D,4D,9A), V(55,33,33,66), V(94,85,85,11), \
V(CF,45,45,8A), V(10,F9,F9,E9), V(06,02,02,04), V(81,7F,7F,FE), \
V(F0,50,50,A0), V(44,3C,3C,78), V(BA,9F,9F,25), V(E3,A8,A8,4B), \
V(F3,51,51,A2), V(FE,A3,A3,5D), V(C0,40,40,80), V(8A,8F,8F,05), \
V(AD,92,92,3F), V(BC,9D,9D,21), V(48,38,38,70), V(04,F5,F5,F1), \
V(DF,BC,BC,63), V(C1,B6,B6,77), V(75,DA,DA,AF), V(63,21,21,42), \
V(30,10,10,20), V(1A,FF,FF,E5), V(0E,F3,F3,FD), V(6D,D2,D2,BF), \
V(4C,CD,CD,81), V(14,0C,0C,18), V(35,13,13,26), V(2F,EC,EC,C3), \
V(E1,5F,5F,BE), V(A2,97,97,35), V(CC,44,44,88), V(39,17,17,2E), \
V(57,C4,C4,93), V(F2,A7,A7,55), V(82,7E,7E,FC), V(47,3D,3D,7A), \
V(AC,64,64,C8), V(E7,5D,5D,BA), V(2B,19,19,32), V(95,73,73,E6), \
V(A0,60,60,C0), V(98,81,81,19), V(D1,4F,4F,9E), V(7F,DC,DC,A3), \
V(66,22,22,44), V(7E,2A,2A,54), V(AB,90,90,3B), V(83,88,88,0B), \
V(CA,46,46,8C), V(29,EE,EE,C7), V(D3,B8,B8,6B), V(3C,14,14,28), \
V(79,DE,DE,A7), V(E2,5E,5E,BC), V(1D,0B,0B,16), V(76,DB,DB,AD), \
V(3B,E0,E0,DB), V(56,32,32,64), V(4E,3A,3A,74), V(1E,0A,0A,14), \
V(DB,49,49,92), V(0A,06,06,0C), V(6C,24,24,48), V(E4,5C,5C,B8), \
V(5D,C2,C2,9F), V(6E,D3,D3,BD), V(EF,AC,AC,43), V(A6,62,62,C4), \
V(A8,91,91,39), V(A4,95,95,31), V(37,E4,E4,D3), V(8B,79,79,F2), \
V(32,E7,E7,D5), V(43,C8,C8,8B), V(59,37,37,6E), V(B7,6D,6D,DA), \
V(8C,8D,8D,01), V(64,D5,D5,B1), V(D2,4E,4E,9C), V(E0,A9,A9,49), \
V(B4,6C,6C,D8), V(FA,56,56,AC), V(07,F4,F4,F3), V(25,EA,EA,CF), \
V(AF,65,65,CA), V(8E,7A,7A,F4), V(E9,AE,AE,47), V(18,08,08,10), \
V(D5,BA,BA,6F), V(88,78,78,F0), V(6F,25,25,4A), V(72,2E,2E,5C), \
V(24,1C,1C,38), V(F1,A6,A6,57), V(C7,B4,B4,73), V(51,C6,C6,97), \
V(23,E8,E8,CB), V(7C,DD,DD,A1), V(9C,74,74,E8), V(21,1F,1F,3E), \
V(DD,4B,4B,96), V(DC,BD,BD,61), V(86,8B,8B,0D), V(85,8A,8A,0F), \
V(90,70,70,E0), V(42,3E,3E,7C), V(C4,B5,B5,71), V(AA,66,66,CC), \
V(D8,48,48,90), V(05,03,03,06), V(01,F6,F6,F7), V(12,0E,0E,1C), \
V(A3,61,61,C2), V(5F,35,35,6A), V(F9,57,57,AE), V(D0,B9,B9,69), \
V(91,86,86,17), V(58,C1,C1,99), V(27,1D,1D,3A), V(B9,9E,9E,27), \
V(38,E1,E1,D9), V(13,F8,F8,EB), V(B3,98,98,2B), V(33,11,11,22), \
V(BB,69,69,D2), V(70,D9,D9,A9), V(89,8E,8E,07), V(A7,94,94,33), \
V(B6,9B,9B,2D), V(22,1E,1E,3C), V(92,87,87,15), V(20,E9,E9,C9), \
V(49,CE,CE,87), V(FF,55,55,AA), V(78,28,28,50), V(7A,DF,DF,A5), \
V(8F,8C,8C,03), V(F8,A1,A1,59), V(80,89,89,09), V(17,0D,0D,1A), \
V(DA,BF,BF,65), V(31,E6,E6,D7), V(C6,42,42,84), V(B8,68,68,D0), \
V(C3,41,41,82), V(B0,99,99,29), V(77,2D,2D,5A), V(11,0F,0F,1E), \
V(CB,B0,B0,7B), V(FC,54,54,A8), V(D6,BB,BB,6D), V(3A,16,16,2C)
#define V(a,b,c,d) 0x##a##b##c##d
static const uint32_t FT0[256] ICACHE_RODATA_ATTR STORE_ATTR = { FT };
#undef V
#define V(a,b,c,d) 0x##b##c##d##a
static const uint32_t FT1[256] ICACHE_RODATA_ATTR STORE_ATTR = { FT };
#undef V
#define V(a,b,c,d) 0x##c##d##a##b
static const uint32_t FT2[256] ICACHE_RODATA_ATTR STORE_ATTR = { FT };
#undef V
#define V(a,b,c,d) 0x##d##a##b##c
static const uint32_t FT3[256] ICACHE_RODATA_ATTR STORE_ATTR = { FT };
#undef V
#undef FT
/*
* Reverse S-box
*/
static const unsigned char RSb[256] ICACHE_RODATA_ATTR STORE_ATTR =
{
0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38,
0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87,
0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D,
0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2,
0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16,
0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA,
0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A,
0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02,
0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA,
0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85,
0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89,
0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20,
0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31,
0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D,
0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0,
0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26,
0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
};
/*
* Reverse tables
*/
#define RT \
\
V(50,A7,F4,51), V(53,65,41,7E), V(C3,A4,17,1A), V(96,5E,27,3A), \
V(CB,6B,AB,3B), V(F1,45,9D,1F), V(AB,58,FA,AC), V(93,03,E3,4B), \
V(55,FA,30,20), V(F6,6D,76,AD), V(91,76,CC,88), V(25,4C,02,F5), \
V(FC,D7,E5,4F), V(D7,CB,2A,C5), V(80,44,35,26), V(8F,A3,62,B5), \
V(49,5A,B1,DE), V(67,1B,BA,25), V(98,0E,EA,45), V(E1,C0,FE,5D), \
V(02,75,2F,C3), V(12,F0,4C,81), V(A3,97,46,8D), V(C6,F9,D3,6B), \
V(E7,5F,8F,03), V(95,9C,92,15), V(EB,7A,6D,BF), V(DA,59,52,95), \
V(2D,83,BE,D4), V(D3,21,74,58), V(29,69,E0,49), V(44,C8,C9,8E), \
V(6A,89,C2,75), V(78,79,8E,F4), V(6B,3E,58,99), V(DD,71,B9,27), \
V(B6,4F,E1,BE), V(17,AD,88,F0), V(66,AC,20,C9), V(B4,3A,CE,7D), \
V(18,4A,DF,63), V(82,31,1A,E5), V(60,33,51,97), V(45,7F,53,62), \
V(E0,77,64,B1), V(84,AE,6B,BB), V(1C,A0,81,FE), V(94,2B,08,F9), \
V(58,68,48,70), V(19,FD,45,8F), V(87,6C,DE,94), V(B7,F8,7B,52), \
V(23,D3,73,AB), V(E2,02,4B,72), V(57,8F,1F,E3), V(2A,AB,55,66), \
V(07,28,EB,B2), V(03,C2,B5,2F), V(9A,7B,C5,86), V(A5,08,37,D3), \
V(F2,87,28,30), V(B2,A5,BF,23), V(BA,6A,03,02), V(5C,82,16,ED), \
V(2B,1C,CF,8A), V(92,B4,79,A7), V(F0,F2,07,F3), V(A1,E2,69,4E), \
V(CD,F4,DA,65), V(D5,BE,05,06), V(1F,62,34,D1), V(8A,FE,A6,C4), \
V(9D,53,2E,34), V(A0,55,F3,A2), V(32,E1,8A,05), V(75,EB,F6,A4), \
V(39,EC,83,0B), V(AA,EF,60,40), V(06,9F,71,5E), V(51,10,6E,BD), \
V(F9,8A,21,3E), V(3D,06,DD,96), V(AE,05,3E,DD), V(46,BD,E6,4D), \
V(B5,8D,54,91), V(05,5D,C4,71), V(6F,D4,06,04), V(FF,15,50,60), \
V(24,FB,98,19), V(97,E9,BD,D6), V(CC,43,40,89), V(77,9E,D9,67), \
V(BD,42,E8,B0), V(88,8B,89,07), V(38,5B,19,E7), V(DB,EE,C8,79), \
V(47,0A,7C,A1), V(E9,0F,42,7C), V(C9,1E,84,F8), V(00,00,00,00), \
V(83,86,80,09), V(48,ED,2B,32), V(AC,70,11,1E), V(4E,72,5A,6C), \
V(FB,FF,0E,FD), V(56,38,85,0F), V(1E,D5,AE,3D), V(27,39,2D,36), \
V(64,D9,0F,0A), V(21,A6,5C,68), V(D1,54,5B,9B), V(3A,2E,36,24), \
V(B1,67,0A,0C), V(0F,E7,57,93), V(D2,96,EE,B4), V(9E,91,9B,1B), \
V(4F,C5,C0,80), V(A2,20,DC,61), V(69,4B,77,5A), V(16,1A,12,1C), \
V(0A,BA,93,E2), V(E5,2A,A0,C0), V(43,E0,22,3C), V(1D,17,1B,12), \
V(0B,0D,09,0E), V(AD,C7,8B,F2), V(B9,A8,B6,2D), V(C8,A9,1E,14), \
V(85,19,F1,57), V(4C,07,75,AF), V(BB,DD,99,EE), V(FD,60,7F,A3), \
V(9F,26,01,F7), V(BC,F5,72,5C), V(C5,3B,66,44), V(34,7E,FB,5B), \
V(76,29,43,8B), V(DC,C6,23,CB), V(68,FC,ED,B6), V(63,F1,E4,B8), \
V(CA,DC,31,D7), V(10,85,63,42), V(40,22,97,13), V(20,11,C6,84), \
V(7D,24,4A,85), V(F8,3D,BB,D2), V(11,32,F9,AE), V(6D,A1,29,C7), \
V(4B,2F,9E,1D), V(F3,30,B2,DC), V(EC,52,86,0D), V(D0,E3,C1,77), \
V(6C,16,B3,2B), V(99,B9,70,A9), V(FA,48,94,11), V(22,64,E9,47), \
V(C4,8C,FC,A8), V(1A,3F,F0,A0), V(D8,2C,7D,56), V(EF,90,33,22), \
V(C7,4E,49,87), V(C1,D1,38,D9), V(FE,A2,CA,8C), V(36,0B,D4,98), \
V(CF,81,F5,A6), V(28,DE,7A,A5), V(26,8E,B7,DA), V(A4,BF,AD,3F), \
V(E4,9D,3A,2C), V(0D,92,78,50), V(9B,CC,5F,6A), V(62,46,7E,54), \
V(C2,13,8D,F6), V(E8,B8,D8,90), V(5E,F7,39,2E), V(F5,AF,C3,82), \
V(BE,80,5D,9F), V(7C,93,D0,69), V(A9,2D,D5,6F), V(B3,12,25,CF), \
V(3B,99,AC,C8), V(A7,7D,18,10), V(6E,63,9C,E8), V(7B,BB,3B,DB), \
V(09,78,26,CD), V(F4,18,59,6E), V(01,B7,9A,EC), V(A8,9A,4F,83), \
V(65,6E,95,E6), V(7E,E6,FF,AA), V(08,CF,BC,21), V(E6,E8,15,EF), \
V(D9,9B,E7,BA), V(CE,36,6F,4A), V(D4,09,9F,EA), V(D6,7C,B0,29), \
V(AF,B2,A4,31), V(31,23,3F,2A), V(30,94,A5,C6), V(C0,66,A2,35), \
V(37,BC,4E,74), V(A6,CA,82,FC), V(B0,D0,90,E0), V(15,D8,A7,33), \
V(4A,98,04,F1), V(F7,DA,EC,41), V(0E,50,CD,7F), V(2F,F6,91,17), \
V(8D,D6,4D,76), V(4D,B0,EF,43), V(54,4D,AA,CC), V(DF,04,96,E4), \
V(E3,B5,D1,9E), V(1B,88,6A,4C), V(B8,1F,2C,C1), V(7F,51,65,46), \
V(04,EA,5E,9D), V(5D,35,8C,01), V(73,74,87,FA), V(2E,41,0B,FB), \
V(5A,1D,67,B3), V(52,D2,DB,92), V(33,56,10,E9), V(13,47,D6,6D), \
V(8C,61,D7,9A), V(7A,0C,A1,37), V(8E,14,F8,59), V(89,3C,13,EB), \
V(EE,27,A9,CE), V(35,C9,61,B7), V(ED,E5,1C,E1), V(3C,B1,47,7A), \
V(59,DF,D2,9C), V(3F,73,F2,55), V(79,CE,14,18), V(BF,37,C7,73), \
V(EA,CD,F7,53), V(5B,AA,FD,5F), V(14,6F,3D,DF), V(86,DB,44,78), \
V(81,F3,AF,CA), V(3E,C4,68,B9), V(2C,34,24,38), V(5F,40,A3,C2), \
V(72,C3,1D,16), V(0C,25,E2,BC), V(8B,49,3C,28), V(41,95,0D,FF), \
V(71,01,A8,39), V(DE,B3,0C,08), V(9C,E4,B4,D8), V(90,C1,56,64), \
V(61,84,CB,7B), V(70,B6,32,D5), V(74,5C,6C,48), V(42,57,B8,D0)
#define V(a,b,c,d) 0x##a##b##c##d
static const uint32_t RT0[256] ICACHE_RODATA_ATTR STORE_ATTR = { RT };
#undef V
#define V(a,b,c,d) 0x##b##c##d##a
static const uint32_t RT1[256] ICACHE_RODATA_ATTR STORE_ATTR = { RT };
#undef V
#define V(a,b,c,d) 0x##c##d##a##b
static const uint32_t RT2[256] ICACHE_RODATA_ATTR STORE_ATTR = { RT };
#undef V
#define V(a,b,c,d) 0x##d##a##b##c
static const uint32_t RT3[256] ICACHE_RODATA_ATTR STORE_ATTR = { RT };
#undef V
#undef RT
/*
* Round constants
*/
static const uint32_t RCON[10] ICACHE_RODATA_ATTR =
{
0x00000001, 0x00000002, 0x00000004, 0x00000008,
0x00000010, 0x00000020, 0x00000040, 0x00000080,
0x0000001B, 0x00000036
};
#else /* MBEDTLS_AES_ROM_TABLES */
/*
* Forward S-box & tables
*/
static unsigned char FSb[256];
static uint32_t FT0[256];
static uint32_t FT1[256];
static uint32_t FT2[256];
static uint32_t FT3[256];
/*
* Reverse S-box & tables
*/
static unsigned char RSb[256];
static uint32_t RT0[256];
static uint32_t RT1[256];
static uint32_t RT2[256];
static uint32_t RT3[256];
/*
* Round constants
*/
static uint32_t RCON[10];
/*
* Tables generation code
*/
#define ROTL8(x) ( ( x << 8 ) & 0xFFFFFFFF ) | ( x >> 24 )
#define XTIME(x) ( ( x << 1 ) ^ ( ( x & 0x80 ) ? 0x1B : 0x00 ) )
#define MUL(x,y) ( ( x && y ) ? pow[(log[x]+log[y]) % 255] : 0 )
static int aes_init_done = 0;
static void aes_gen_tables( void )
{
int i, x, y, z;
int pow[256];
int log[256];
/*
* compute pow and log tables over GF(2^8)
*/
for( i = 0, x = 1; i < 256; i++ )
{
pow[i] = x;
log[x] = i;
x = ( x ^ XTIME( x ) ) & 0xFF;
}
/*
* calculate the round constants
*/
for( i = 0, x = 1; i < 10; i++ )
{
RCON[i] = (uint32_t) x;
x = XTIME( x ) & 0xFF;
}
/*
* generate the forward and reverse S-boxes
*/
FSb[0x00] = 0x63;
RSb[0x63] = 0x00;
for( i = 1; i < 256; i++ )
{
x = pow[255 - log[i]];
y = x; y = ( ( y << 1 ) | ( y >> 7 ) ) & 0xFF;
x ^= y; y = ( ( y << 1 ) | ( y >> 7 ) ) & 0xFF;
x ^= y; y = ( ( y << 1 ) | ( y >> 7 ) ) & 0xFF;
x ^= y; y = ( ( y << 1 ) | ( y >> 7 ) ) & 0xFF;
x ^= y ^ 0x63;
FSb[i] = (unsigned char) x;
RSb[x] = (unsigned char) i;
}
/*
* generate the forward and reverse tables
*/
for( i = 0; i < 256; i++ )
{
x = FSb[i];
y = XTIME( x ) & 0xFF;
z = ( y ^ x ) & 0xFF;
FT0[i] = ( (uint32_t) y ) ^
( (uint32_t) x << 8 ) ^
( (uint32_t) x << 16 ) ^
( (uint32_t) z << 24 );
FT1[i] = ROTL8( FT0[i] );
FT2[i] = ROTL8( FT1[i] );
FT3[i] = ROTL8( FT2[i] );
x = RSb[i];
RT0[i] = ( (uint32_t) MUL( 0x0E, x ) ) ^
( (uint32_t) MUL( 0x09, x ) << 8 ) ^
( (uint32_t) MUL( 0x0D, x ) << 16 ) ^
( (uint32_t) MUL( 0x0B, x ) << 24 );
RT1[i] = ROTL8( RT0[i] );
RT2[i] = ROTL8( RT1[i] );
RT3[i] = ROTL8( RT2[i] );
}
}
#endif /* MBEDTLS_AES_ROM_TABLES */
void mbedtls_aes_init( mbedtls_aes_context *ctx )
{
memset( ctx, 0, sizeof( mbedtls_aes_context ) );
}
void mbedtls_aes_free( mbedtls_aes_context *ctx )
{
if( ctx == NULL )
return;
mbedtls_zeroize( ctx, sizeof( mbedtls_aes_context ) );
}
/*
* AES key schedule (encryption)
*/
#if !defined(MBEDTLS_AES_SETKEY_ENC_ALT)
int mbedtls_aes_setkey_enc( mbedtls_aes_context *ctx, const unsigned char *key,
unsigned int keybits )
{
unsigned int i;
uint32_t *RK;
#if !defined(MBEDTLS_AES_ROM_TABLES)
if( aes_init_done == 0 )
{
aes_gen_tables();
aes_init_done = 1;
}
#endif
switch( keybits )
{
case 128: ctx->nr = 10; break;
case 192: ctx->nr = 12; break;
case 256: ctx->nr = 14; break;
default : return( MBEDTLS_ERR_AES_INVALID_KEY_LENGTH );
}
#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_PADLOCK_ALIGN16)
if( aes_padlock_ace == -1 )
aes_padlock_ace = mbedtls_padlock_has_support( MBEDTLS_PADLOCK_ACE );
if( aes_padlock_ace )
ctx->rk = RK = MBEDTLS_PADLOCK_ALIGN16( ctx->buf );
else
#endif
ctx->rk = RK = ctx->buf;
#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64)
if( mbedtls_aesni_has_support( MBEDTLS_AESNI_AES ) )
return( mbedtls_aesni_setkey_enc( (unsigned char *) ctx->rk, key, keybits ) );
#endif
for( i = 0; i < ( keybits >> 5 ); i++ )
{
GET_UINT32_LE( RK[i], key, i << 2 );
}
switch( ctx->nr )
{
case 10:
for( i = 0; i < 10; i++, RK += 4 )
{
RK[4] = RK[0] ^ RCON[i] ^
( (uint32_t) system_get_data_of_array_8(FSb ,( RK[3] >> 8 ) & 0xFF ) ) ^
( (uint32_t) system_get_data_of_array_8(FSb ,( RK[3] >> 16 ) & 0xFF ) << 8 ) ^
( (uint32_t) system_get_data_of_array_8(FSb ,( RK[3] >> 24 ) & 0xFF ) << 16 ) ^
( (uint32_t) system_get_data_of_array_8(FSb ,( RK[3] ) & 0xFF ) << 24 );
RK[5] = RK[1] ^ RK[4];
RK[6] = RK[2] ^ RK[5];
RK[7] = RK[3] ^ RK[6];
}
break;
case 12:
for( i = 0; i < 8; i++, RK += 6 )
{
RK[6] = RK[0] ^ RCON[i] ^
( (uint32_t) system_get_data_of_array_8(FSb, ( RK[5] >> 8 ) & 0xFF ) ) ^
( (uint32_t) system_get_data_of_array_8(FSb, ( RK[5] >> 16 ) & 0xFF ) << 8 ) ^
( (uint32_t) system_get_data_of_array_8(FSb, ( RK[5] >> 24 ) & 0xFF ) << 16 ) ^
( (uint32_t) system_get_data_of_array_8(FSb, ( RK[5] ) & 0xFF ) << 24 );
RK[7] = RK[1] ^ RK[6];
RK[8] = RK[2] ^ RK[7];
RK[9] = RK[3] ^ RK[8];
RK[10] = RK[4] ^ RK[9];
RK[11] = RK[5] ^ RK[10];
}
break;
case 14:
for( i = 0; i < 7; i++, RK += 8 )
{
RK[8] = RK[0] ^ RCON[i] ^
( (uint32_t) system_get_data_of_array_8(FSb, ( RK[7] >> 8 ) & 0xFF ) ) ^
( (uint32_t) system_get_data_of_array_8(FSb, ( RK[7] >> 16 ) & 0xFF ) << 8 ) ^
( (uint32_t) system_get_data_of_array_8(FSb, ( RK[7] >> 24 ) & 0xFF ) << 16 ) ^
( (uint32_t) system_get_data_of_array_8(FSb, ( RK[7] ) & 0xFF ) << 24 );
RK[9] = RK[1] ^ RK[8];
RK[10] = RK[2] ^ RK[9];
RK[11] = RK[3] ^ RK[10];
RK[12] = RK[4] ^
( (uint32_t) system_get_data_of_array_8(FSb, ( RK[11] ) & 0xFF ) ) ^
( (uint32_t) system_get_data_of_array_8(FSb, ( RK[11] >> 8 ) & 0xFF ) << 8 ) ^
( (uint32_t) system_get_data_of_array_8(FSb, ( RK[11] >> 16 ) & 0xFF ) << 16 ) ^
( (uint32_t) system_get_data_of_array_8(FSb, ( RK[11] >> 24 ) & 0xFF ) << 24 );
RK[13] = RK[5] ^ RK[12];
RK[14] = RK[6] ^ RK[13];
RK[15] = RK[7] ^ RK[14];
}
break;
}
return( 0 );
}
#endif /* !MBEDTLS_AES_SETKEY_ENC_ALT */
/*
* AES key schedule (decryption)
*/
#if !defined(MBEDTLS_AES_SETKEY_DEC_ALT)
int mbedtls_aes_setkey_dec( mbedtls_aes_context *ctx, const unsigned char *key,
unsigned int keybits )
{
int i, j, ret;
mbedtls_aes_context cty;
uint32_t *RK;
uint32_t *SK;
mbedtls_aes_init( &cty );
#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_PADLOCK_ALIGN16)
if( aes_padlock_ace == -1 )
aes_padlock_ace = mbedtls_padlock_has_support( MBEDTLS_PADLOCK_ACE );
if( aes_padlock_ace )
ctx->rk = RK = MBEDTLS_PADLOCK_ALIGN16( ctx->buf );
else
#endif
ctx->rk = RK = ctx->buf;
/* Also checks keybits */
if( ( ret = mbedtls_aes_setkey_enc( &cty, key, keybits ) ) != 0 )
goto exit;
ctx->nr = cty.nr;
#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64)
if( mbedtls_aesni_has_support( MBEDTLS_AESNI_AES ) )
{
mbedtls_aesni_inverse_key( (unsigned char *) ctx->rk,
(const unsigned char *) cty.rk, ctx->nr );
goto exit;
}
#endif
SK = cty.rk + cty.nr * 4;
*RK++ = *SK++;
*RK++ = *SK++;
*RK++ = *SK++;
*RK++ = *SK++;
for( i = ctx->nr - 1, SK -= 8; i > 0; i--, SK -= 8 )
{
for( j = 0; j < 4; j++, SK++ )
{
*RK++ = RT0[ system_get_data_of_array_8(FSb, ( *SK ) & 0xFF ) ] ^
RT1[ system_get_data_of_array_8(FSb, ( *SK >> 8 ) & 0xFF ) ] ^
RT2[ system_get_data_of_array_8(FSb, ( *SK >> 16 ) & 0xFF ) ] ^
RT3[ system_get_data_of_array_8(FSb, ( *SK >> 24 ) & 0xFF ) ];
}
}
*RK++ = *SK++;
*RK++ = *SK++;
*RK++ = *SK++;
*RK++ = *SK++;
exit:
mbedtls_aes_free( &cty );
return( ret );
}
#endif /* !MBEDTLS_AES_SETKEY_DEC_ALT */
#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \
{ \
X0 = *RK++ ^ FT0[ ( Y0 ) & 0xFF ] ^ \
FT1[ ( Y1 >> 8 ) & 0xFF ] ^ \
FT2[ ( Y2 >> 16 ) & 0xFF ] ^ \
FT3[ ( Y3 >> 24 ) & 0xFF ]; \
\
X1 = *RK++ ^ FT0[ ( Y1 ) & 0xFF ] ^ \
FT1[ ( Y2 >> 8 ) & 0xFF ] ^ \
FT2[ ( Y3 >> 16 ) & 0xFF ] ^ \
FT3[ ( Y0 >> 24 ) & 0xFF ]; \
\
X2 = *RK++ ^ FT0[ ( Y2 ) & 0xFF ] ^ \
FT1[ ( Y3 >> 8 ) & 0xFF ] ^ \
FT2[ ( Y0 >> 16 ) & 0xFF ] ^ \
FT3[ ( Y1 >> 24 ) & 0xFF ]; \
\
X3 = *RK++ ^ FT0[ ( Y3 ) & 0xFF ] ^ \
FT1[ ( Y0 >> 8 ) & 0xFF ] ^ \
FT2[ ( Y1 >> 16 ) & 0xFF ] ^ \
FT3[ ( Y2 >> 24 ) & 0xFF ]; \
}
#define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \
{ \
X0 = *RK++ ^ RT0[ ( Y0 ) & 0xFF ] ^ \
RT1[ ( Y3 >> 8 ) & 0xFF ] ^ \
RT2[ ( Y2 >> 16 ) & 0xFF ] ^ \
RT3[ ( Y1 >> 24 ) & 0xFF ]; \
\
X1 = *RK++ ^ RT0[ ( Y1 ) & 0xFF ] ^ \
RT1[ ( Y0 >> 8 ) & 0xFF ] ^ \
RT2[ ( Y3 >> 16 ) & 0xFF ] ^ \
RT3[ ( Y2 >> 24 ) & 0xFF ]; \
\
X2 = *RK++ ^ RT0[ ( Y2 ) & 0xFF ] ^ \
RT1[ ( Y1 >> 8 ) & 0xFF ] ^ \
RT2[ ( Y0 >> 16 ) & 0xFF ] ^ \
RT3[ ( Y3 >> 24 ) & 0xFF ]; \
\
X3 = *RK++ ^ RT0[ ( Y3 ) & 0xFF ] ^ \
RT1[ ( Y2 >> 8 ) & 0xFF ] ^ \
RT2[ ( Y1 >> 16 ) & 0xFF ] ^ \
RT3[ ( Y0 >> 24 ) & 0xFF ]; \
}
/*
* AES-ECB block encryption
*/
#if !defined(MBEDTLS_AES_ENCRYPT_ALT)
void mbedtls_aes_encrypt( mbedtls_aes_context *ctx,
const unsigned char input[16],
unsigned char output[16] )
{
int i;
uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3;
RK = ctx->rk;
GET_UINT32_LE( X0, input, 0 ); X0 ^= *RK++;
GET_UINT32_LE( X1, input, 4 ); X1 ^= *RK++;
GET_UINT32_LE( X2, input, 8 ); X2 ^= *RK++;
GET_UINT32_LE( X3, input, 12 ); X3 ^= *RK++;
for( i = ( ctx->nr >> 1 ) - 1; i > 0; i-- )
{
AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 );
AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 );
}
AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 );
X0 = *RK++ ^ \
( (uint32_t) system_get_data_of_array_8(FSb, ( Y0 ) & 0xFF ) ) ^
( (uint32_t) system_get_data_of_array_8(FSb, ( Y1 >> 8 ) & 0xFF ) << 8 ) ^
( (uint32_t) system_get_data_of_array_8(FSb, ( Y2 >> 16 ) & 0xFF ) << 16 ) ^
( (uint32_t) system_get_data_of_array_8(FSb, ( Y3 >> 24 ) & 0xFF ) << 24 );
X1 = *RK++ ^ \
( (uint32_t) system_get_data_of_array_8(FSb, ( Y1 ) & 0xFF ) ) ^
( (uint32_t) system_get_data_of_array_8(FSb, ( Y2 >> 8 ) & 0xFF ) << 8 ) ^
( (uint32_t) system_get_data_of_array_8(FSb, ( Y3 >> 16 ) & 0xFF ) << 16 ) ^
( (uint32_t) system_get_data_of_array_8(FSb, ( Y0 >> 24 ) & 0xFF ) << 24 );
X2 = *RK++ ^ \
( (uint32_t) system_get_data_of_array_8(FSb, ( Y2 ) & 0xFF ) ) ^
( (uint32_t) system_get_data_of_array_8(FSb, ( Y3 >> 8 ) & 0xFF ) << 8 ) ^
( (uint32_t) system_get_data_of_array_8(FSb, ( Y0 >> 16 ) & 0xFF ) << 16 ) ^
( (uint32_t) system_get_data_of_array_8(FSb, ( Y1 >> 24 ) & 0xFF ) << 24 );
X3 = *RK++ ^ \
( (uint32_t) system_get_data_of_array_8(FSb, ( Y3 ) & 0xFF ) ) ^
( (uint32_t) system_get_data_of_array_8(FSb, ( Y0 >> 8 ) & 0xFF ) << 8 ) ^
( (uint32_t) system_get_data_of_array_8(FSb, ( Y1 >> 16 ) & 0xFF ) << 16 ) ^
( (uint32_t) system_get_data_of_array_8(FSb, ( Y2 >> 24 ) & 0xFF ) << 24 );
PUT_UINT32_LE( X0, output, 0 );
PUT_UINT32_LE( X1, output, 4 );
PUT_UINT32_LE( X2, output, 8 );
PUT_UINT32_LE( X3, output, 12 );
}
#endif /* !MBEDTLS_AES_ENCRYPT_ALT */
/*
* AES-ECB block decryption
*/
#if !defined(MBEDTLS_AES_DECRYPT_ALT)
void mbedtls_aes_decrypt( mbedtls_aes_context *ctx,
const unsigned char input[16],
unsigned char output[16] )
{
int i;
uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3;
RK = ctx->rk;
GET_UINT32_LE( X0, input, 0 ); X0 ^= *RK++;
GET_UINT32_LE( X1, input, 4 ); X1 ^= *RK++;
GET_UINT32_LE( X2, input, 8 ); X2 ^= *RK++;
GET_UINT32_LE( X3, input, 12 ); X3 ^= *RK++;
for( i = ( ctx->nr >> 1 ) - 1; i > 0; i-- )
{
AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 );
AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 );
}
AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 );
X0 = *RK++ ^ \
( (uint32_t) system_get_data_of_array_8(RSb, ( Y0 ) & 0xFF ) ) ^
( (uint32_t) system_get_data_of_array_8(RSb, ( Y3 >> 8 ) & 0xFF ) << 8 ) ^
( (uint32_t) system_get_data_of_array_8(RSb, ( Y2 >> 16 ) & 0xFF ) << 16 ) ^
( (uint32_t) system_get_data_of_array_8(RSb, ( Y1 >> 24 ) & 0xFF ) << 24 );
X1 = *RK++ ^ \
( (uint32_t) system_get_data_of_array_8(RSb, ( Y1 ) & 0xFF ) ) ^
( (uint32_t) system_get_data_of_array_8(RSb, ( Y0 >> 8 ) & 0xFF ) << 8 ) ^
( (uint32_t) system_get_data_of_array_8(RSb, ( Y3 >> 16 ) & 0xFF ) << 16 ) ^
( (uint32_t) system_get_data_of_array_8(RSb, ( Y2 >> 24 ) & 0xFF ) << 24 );
X2 = *RK++ ^ \
( (uint32_t) system_get_data_of_array_8(RSb, ( Y2 ) & 0xFF ) ) ^
( (uint32_t) system_get_data_of_array_8(RSb, ( Y1 >> 8 ) & 0xFF ) << 8 ) ^
( (uint32_t) system_get_data_of_array_8(RSb, ( Y0 >> 16 ) & 0xFF ) << 16 ) ^
( (uint32_t) system_get_data_of_array_8(RSb, ( Y3 >> 24 ) & 0xFF ) << 24 );
X3 = *RK++ ^ \
( (uint32_t) system_get_data_of_array_8(RSb, ( Y3 ) & 0xFF ) ) ^
( (uint32_t) system_get_data_of_array_8(RSb, ( Y2 >> 8 ) & 0xFF ) << 8 ) ^
( (uint32_t) system_get_data_of_array_8(RSb, ( Y1 >> 16 ) & 0xFF ) << 16 ) ^
( (uint32_t) system_get_data_of_array_8(RSb, ( Y0 >> 24 ) & 0xFF ) << 24 );
PUT_UINT32_LE( X0, output, 0 );
PUT_UINT32_LE( X1, output, 4 );
PUT_UINT32_LE( X2, output, 8 );
PUT_UINT32_LE( X3, output, 12 );
}
#endif /* !MBEDTLS_AES_DECRYPT_ALT */
/*
* AES-ECB block encryption/decryption
*/
int mbedtls_aes_crypt_ecb( mbedtls_aes_context *ctx,
int mode,
const unsigned char input[16],
unsigned char output[16] )
{
#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64)
if( mbedtls_aesni_has_support( MBEDTLS_AESNI_AES ) )
return( mbedtls_aesni_crypt_ecb( ctx, mode, input, output ) );
#endif
#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_HAVE_X86)
if( aes_padlock_ace )
{
if( mbedtls_padlock_xcryptecb( ctx, mode, input, output ) == 0 )
return( 0 );
// If padlock data misaligned, we just fall back to
// unaccelerated mode
//
}
#endif
if( mode == MBEDTLS_AES_ENCRYPT )
mbedtls_aes_encrypt( ctx, input, output );
else
mbedtls_aes_decrypt( ctx, input, output );
return( 0 );
}
#if defined(MBEDTLS_CIPHER_MODE_CBC)
/*
* AES-CBC buffer encryption/decryption
*/
int mbedtls_aes_crypt_cbc( mbedtls_aes_context *ctx,
int mode,
size_t length,
unsigned char iv[16],
const unsigned char *input,
unsigned char *output )
{
int i;
unsigned char temp[16];
if( length % 16 )
return( MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH );
#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_HAVE_X86)
if( aes_padlock_ace )
{
if( mbedtls_padlock_xcryptcbc( ctx, mode, length, iv, input, output ) == 0 )
return( 0 );
// If padlock data misaligned, we just fall back to
// unaccelerated mode
//
}
#endif
if( mode == MBEDTLS_AES_DECRYPT )
{
while( length > 0 )
{
memcpy( temp, input, 16 );
mbedtls_aes_crypt_ecb( ctx, mode, input, output );
for( i = 0; i < 16; i++ )
output[i] = (unsigned char)( output[i] ^ iv[i] );
memcpy( iv, temp, 16 );
input += 16;
output += 16;
length -= 16;
}
}
else
{
while( length > 0 )
{
for( i = 0; i < 16; i++ )
output[i] = (unsigned char)( input[i] ^ iv[i] );
mbedtls_aes_crypt_ecb( ctx, mode, output, output );
memcpy( iv, output, 16 );
input += 16;
output += 16;
length -= 16;
}
}
return( 0 );
}
#endif /* MBEDTLS_CIPHER_MODE_CBC */
#if defined(MBEDTLS_CIPHER_MODE_CFB)
/*
* AES-CFB128 buffer encryption/decryption
*/
int mbedtls_aes_crypt_cfb128( mbedtls_aes_context *ctx,
int mode,
size_t length,
size_t *iv_off,
unsigned char iv[16],
const unsigned char *input,
unsigned char *output )
{
int c;
size_t n = *iv_off;
if( mode == MBEDTLS_AES_DECRYPT )
{
while( length-- )
{
if( n == 0 )
mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, iv, iv );
c = *input++;
*output++ = (unsigned char)( c ^ iv[n] );
iv[n] = (unsigned char) c;
n = ( n + 1 ) & 0x0F;
}
}
else
{
while( length-- )
{
if( n == 0 )
mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, iv, iv );
iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ );
n = ( n + 1 ) & 0x0F;
}
}
*iv_off = n;
return( 0 );
}
/*
* AES-CFB8 buffer encryption/decryption
*/
int mbedtls_aes_crypt_cfb8( mbedtls_aes_context *ctx,
int mode,
size_t length,
unsigned char iv[16],
const unsigned char *input,
unsigned char *output )
{
unsigned char c;
unsigned char ov[17];
while( length-- )
{
memcpy( ov, iv, 16 );
mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, iv, iv );
if( mode == MBEDTLS_AES_DECRYPT )
ov[16] = *input;
c = *output++ = (unsigned char)( iv[0] ^ *input++ );
if( mode == MBEDTLS_AES_ENCRYPT )
ov[16] = c;
memcpy( iv, ov + 1, 16 );
}
return( 0 );
}
#endif /*MBEDTLS_CIPHER_MODE_CFB */
#if defined(MBEDTLS_CIPHER_MODE_CTR)
/*
* AES-CTR buffer encryption/decryption
*/
int mbedtls_aes_crypt_ctr( mbedtls_aes_context *ctx,
size_t length,
size_t *nc_off,
unsigned char nonce_counter[16],
unsigned char stream_block[16],
const unsigned char *input,
unsigned char *output )
{
int c, i;
size_t n = *nc_off;
while( length-- )
{
if( n == 0 ) {
mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, nonce_counter, stream_block );
for( i = 16; i > 0; i-- )
if( ++nonce_counter[i - 1] != 0 )
break;
}
c = *input++;
*output++ = (unsigned char)( c ^ stream_block[n] );
n = ( n + 1 ) & 0x0F;
}
*nc_off = n;
return( 0 );
}
#endif /* MBEDTLS_CIPHER_MODE_CTR */
#endif /* !MBEDTLS_AES_ALT */
#if defined(MBEDTLS_SELF_TEST)
/*
* AES test vectors from:
*
* http://csrc.nist.gov/archive/aes/rijndael/rijndael-vals.zip
*/
static const unsigned char aes_test_ecb_dec[3][16] =
{
{ 0x44, 0x41, 0x6A, 0xC2, 0xD1, 0xF5, 0x3C, 0x58,
0x33, 0x03, 0x91, 0x7E, 0x6B, 0xE9, 0xEB, 0xE0 },
{ 0x48, 0xE3, 0x1E, 0x9E, 0x25, 0x67, 0x18, 0xF2,
0x92, 0x29, 0x31, 0x9C, 0x19, 0xF1, 0x5B, 0xA4 },
{ 0x05, 0x8C, 0xCF, 0xFD, 0xBB, 0xCB, 0x38, 0x2D,
0x1F, 0x6F, 0x56, 0x58, 0x5D, 0x8A, 0x4A, 0xDE }
};
static const unsigned char aes_test_ecb_enc[3][16] =
{
{ 0xC3, 0x4C, 0x05, 0x2C, 0xC0, 0xDA, 0x8D, 0x73,
0x45, 0x1A, 0xFE, 0x5F, 0x03, 0xBE, 0x29, 0x7F },
{ 0xF3, 0xF6, 0x75, 0x2A, 0xE8, 0xD7, 0x83, 0x11,
0x38, 0xF0, 0x41, 0x56, 0x06, 0x31, 0xB1, 0x14 },
{ 0x8B, 0x79, 0xEE, 0xCC, 0x93, 0xA0, 0xEE, 0x5D,
0xFF, 0x30, 0xB4, 0xEA, 0x21, 0x63, 0x6D, 0xA4 }
};
#if defined(MBEDTLS_CIPHER_MODE_CBC)
static const unsigned char aes_test_cbc_dec[3][16] =
{
{ 0xFA, 0xCA, 0x37, 0xE0, 0xB0, 0xC8, 0x53, 0x73,
0xDF, 0x70, 0x6E, 0x73, 0xF7, 0xC9, 0xAF, 0x86 },
{ 0x5D, 0xF6, 0x78, 0xDD, 0x17, 0xBA, 0x4E, 0x75,
0xB6, 0x17, 0x68, 0xC6, 0xAD, 0xEF, 0x7C, 0x7B },
{ 0x48, 0x04, 0xE1, 0x81, 0x8F, 0xE6, 0x29, 0x75,
0x19, 0xA3, 0xE8, 0x8C, 0x57, 0x31, 0x04, 0x13 }
};
static const unsigned char aes_test_cbc_enc[3][16] =
{
{ 0x8A, 0x05, 0xFC, 0x5E, 0x09, 0x5A, 0xF4, 0x84,
0x8A, 0x08, 0xD3, 0x28, 0xD3, 0x68, 0x8E, 0x3D },
{ 0x7B, 0xD9, 0x66, 0xD5, 0x3A, 0xD8, 0xC1, 0xBB,
0x85, 0xD2, 0xAD, 0xFA, 0xE8, 0x7B, 0xB1, 0x04 },
{ 0xFE, 0x3C, 0x53, 0x65, 0x3E, 0x2F, 0x45, 0xB5,
0x6F, 0xCD, 0x88, 0xB2, 0xCC, 0x89, 0x8F, 0xF0 }
};
#endif /* MBEDTLS_CIPHER_MODE_CBC */
#if defined(MBEDTLS_CIPHER_MODE_CFB)
/*
* AES-CFB128 test vectors from:
*
* http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
*/
static const unsigned char aes_test_cfb128_key[3][32] =
{
{ 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6,
0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C },
{ 0x8E, 0x73, 0xB0, 0xF7, 0xDA, 0x0E, 0x64, 0x52,
0xC8, 0x10, 0xF3, 0x2B, 0x80, 0x90, 0x79, 0xE5,
0x62, 0xF8, 0xEA, 0xD2, 0x52, 0x2C, 0x6B, 0x7B },
{ 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE,
0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81,
0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7,
0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4 }
};
static const unsigned char aes_test_cfb128_iv[16] =
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
};
static const unsigned char aes_test_cfb128_pt[64] =
{
0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96,
0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A,
0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C,
0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51,
0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11,
0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF,
0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B, 0x17,
0xAD, 0x2B, 0x41, 0x7B, 0xE6, 0x6C, 0x37, 0x10
};
static const unsigned char aes_test_cfb128_ct[3][64] =
{
{ 0x3B, 0x3F, 0xD9, 0x2E, 0xB7, 0x2D, 0xAD, 0x20,
0x33, 0x34, 0x49, 0xF8, 0xE8, 0x3C, 0xFB, 0x4A,
0xC8, 0xA6, 0x45, 0x37, 0xA0, 0xB3, 0xA9, 0x3F,
0xCD, 0xE3, 0xCD, 0xAD, 0x9F, 0x1C, 0xE5, 0x8B,
0x26, 0x75, 0x1F, 0x67, 0xA3, 0xCB, 0xB1, 0x40,
0xB1, 0x80, 0x8C, 0xF1, 0x87, 0xA4, 0xF4, 0xDF,
0xC0, 0x4B, 0x05, 0x35, 0x7C, 0x5D, 0x1C, 0x0E,
0xEA, 0xC4, 0xC6, 0x6F, 0x9F, 0xF7, 0xF2, 0xE6 },
{ 0xCD, 0xC8, 0x0D, 0x6F, 0xDD, 0xF1, 0x8C, 0xAB,
0x34, 0xC2, 0x59, 0x09, 0xC9, 0x9A, 0x41, 0x74,
0x67, 0xCE, 0x7F, 0x7F, 0x81, 0x17, 0x36, 0x21,
0x96, 0x1A, 0x2B, 0x70, 0x17, 0x1D, 0x3D, 0x7A,
0x2E, 0x1E, 0x8A, 0x1D, 0xD5, 0x9B, 0x88, 0xB1,
0xC8, 0xE6, 0x0F, 0xED, 0x1E, 0xFA, 0xC4, 0xC9,
0xC0, 0x5F, 0x9F, 0x9C, 0xA9, 0x83, 0x4F, 0xA0,
0x42, 0xAE, 0x8F, 0xBA, 0x58, 0x4B, 0x09, 0xFF },
{ 0xDC, 0x7E, 0x84, 0xBF, 0xDA, 0x79, 0x16, 0x4B,
0x7E, 0xCD, 0x84, 0x86, 0x98, 0x5D, 0x38, 0x60,
0x39, 0xFF, 0xED, 0x14, 0x3B, 0x28, 0xB1, 0xC8,
0x32, 0x11, 0x3C, 0x63, 0x31, 0xE5, 0x40, 0x7B,
0xDF, 0x10, 0x13, 0x24, 0x15, 0xE5, 0x4B, 0x92,
0xA1, 0x3E, 0xD0, 0xA8, 0x26, 0x7A, 0xE2, 0xF9,
0x75, 0xA3, 0x85, 0x74, 0x1A, 0xB9, 0xCE, 0xF8,
0x20, 0x31, 0x62, 0x3D, 0x55, 0xB1, 0xE4, 0x71 }
};
#endif /* MBEDTLS_CIPHER_MODE_CFB */
#if defined(MBEDTLS_CIPHER_MODE_CTR)
/*
* AES-CTR test vectors from:
*
* http://www.faqs.org/rfcs/rfc3686.html
*/
static const unsigned char aes_test_ctr_key[3][16] =
{
{ 0xAE, 0x68, 0x52, 0xF8, 0x12, 0x10, 0x67, 0xCC,
0x4B, 0xF7, 0xA5, 0x76, 0x55, 0x77, 0xF3, 0x9E },
{ 0x7E, 0x24, 0x06, 0x78, 0x17, 0xFA, 0xE0, 0xD7,
0x43, 0xD6, 0xCE, 0x1F, 0x32, 0x53, 0x91, 0x63 },
{ 0x76, 0x91, 0xBE, 0x03, 0x5E, 0x50, 0x20, 0xA8,
0xAC, 0x6E, 0x61, 0x85, 0x29, 0xF9, 0xA0, 0xDC }
};
static const unsigned char aes_test_ctr_nonce_counter[3][16] =
{
{ 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
{ 0x00, 0x6C, 0xB6, 0xDB, 0xC0, 0x54, 0x3B, 0x59,
0xDA, 0x48, 0xD9, 0x0B, 0x00, 0x00, 0x00, 0x01 },
{ 0x00, 0xE0, 0x01, 0x7B, 0x27, 0x77, 0x7F, 0x3F,
0x4A, 0x17, 0x86, 0xF0, 0x00, 0x00, 0x00, 0x01 }
};
static const unsigned char aes_test_ctr_pt[3][48] =
{
{ 0x53, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x62,
0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x6D, 0x73, 0x67 },
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F },
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x20, 0x21, 0x22, 0x23 }
};
static const unsigned char aes_test_ctr_ct[3][48] =
{
{ 0xE4, 0x09, 0x5D, 0x4F, 0xB7, 0xA7, 0xB3, 0x79,
0x2D, 0x61, 0x75, 0xA3, 0x26, 0x13, 0x11, 0xB8 },
{ 0x51, 0x04, 0xA1, 0x06, 0x16, 0x8A, 0x72, 0xD9,
0x79, 0x0D, 0x41, 0xEE, 0x8E, 0xDA, 0xD3, 0x88,
0xEB, 0x2E, 0x1E, 0xFC, 0x46, 0xDA, 0x57, 0xC8,
0xFC, 0xE6, 0x30, 0xDF, 0x91, 0x41, 0xBE, 0x28 },
{ 0xC1, 0xCF, 0x48, 0xA8, 0x9F, 0x2F, 0xFD, 0xD9,
0xCF, 0x46, 0x52, 0xE9, 0xEF, 0xDB, 0x72, 0xD7,
0x45, 0x40, 0xA4, 0x2B, 0xDE, 0x6D, 0x78, 0x36,
0xD5, 0x9A, 0x5C, 0xEA, 0xAE, 0xF3, 0x10, 0x53,
0x25, 0xB2, 0x07, 0x2F }
};
static const int aes_test_ctr_len[3] =
{ 16, 32, 36 };
#endif /* MBEDTLS_CIPHER_MODE_CTR */
/*
* Checkup routine
*/
int mbedtls_aes_self_test( int verbose )
{
int ret = 0, i, j, u, v;
unsigned char key[32];
unsigned char buf[64];
unsigned char iv[16];
#if defined(MBEDTLS_CIPHER_MODE_CBC)
unsigned char prv[16];
#endif
#if defined(MBEDTLS_CIPHER_MODE_CTR) || defined(MBEDTLS_CIPHER_MODE_CFB)
size_t offset;
#endif
#if defined(MBEDTLS_CIPHER_MODE_CTR)
int len;
unsigned char nonce_counter[16];
unsigned char stream_block[16];
#endif
mbedtls_aes_context ctx;
memset( key, 0, 32 );
mbedtls_aes_init( &ctx );
/*
* ECB mode
*/
for( i = 0; i < 6; i++ )
{
u = i >> 1;
v = i & 1;
if( verbose != 0 )
mbedtls_printf( " AES-ECB-%3d (%s): ", 128 + u * 64,
( v == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" );
memset( buf, 0, 16 );
if( v == MBEDTLS_AES_DECRYPT )
{
mbedtls_aes_setkey_dec( &ctx, key, 128 + u * 64 );
for( j = 0; j < 10000; j++ )
mbedtls_aes_crypt_ecb( &ctx, v, buf, buf );
if( memcmp( buf, aes_test_ecb_dec[u], 16 ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
ret = 1;
goto exit;
}
}
else
{
mbedtls_aes_setkey_enc( &ctx, key, 128 + u * 64 );
for( j = 0; j < 10000; j++ )
mbedtls_aes_crypt_ecb( &ctx, v, buf, buf );
if( memcmp( buf, aes_test_ecb_enc[u], 16 ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
ret = 1;
goto exit;
}
}
if( verbose != 0 )
mbedtls_printf( "passed\n" );
}
if( verbose != 0 )
mbedtls_printf( "\n" );
#if defined(MBEDTLS_CIPHER_MODE_CBC)
/*
* CBC mode
*/
for( i = 0; i < 6; i++ )
{
u = i >> 1;
v = i & 1;
if( verbose != 0 )
mbedtls_printf( " AES-CBC-%3d (%s): ", 128 + u * 64,
( v == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" );
memset( iv , 0, 16 );
memset( prv, 0, 16 );
memset( buf, 0, 16 );
if( v == MBEDTLS_AES_DECRYPT )
{
mbedtls_aes_setkey_dec( &ctx, key, 128 + u * 64 );
for( j = 0; j < 10000; j++ )
mbedtls_aes_crypt_cbc( &ctx, v, 16, iv, buf, buf );
if( memcmp( buf, aes_test_cbc_dec[u], 16 ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
ret = 1;
goto exit;
}
}
else
{
mbedtls_aes_setkey_enc( &ctx, key, 128 + u * 64 );
for( j = 0; j < 10000; j++ )
{
unsigned char tmp[16];
mbedtls_aes_crypt_cbc( &ctx, v, 16, iv, buf, buf );
memcpy( tmp, prv, 16 );
memcpy( prv, buf, 16 );
memcpy( buf, tmp, 16 );
}
if( memcmp( prv, aes_test_cbc_enc[u], 16 ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
ret = 1;
goto exit;
}
}
if( verbose != 0 )
mbedtls_printf( "passed\n" );
}
if( verbose != 0 )
mbedtls_printf( "\n" );
#endif /* MBEDTLS_CIPHER_MODE_CBC */
#if defined(MBEDTLS_CIPHER_MODE_CFB)
/*
* CFB128 mode
*/
for( i = 0; i < 6; i++ )
{
u = i >> 1;
v = i & 1;
if( verbose != 0 )
mbedtls_printf( " AES-CFB128-%3d (%s): ", 128 + u * 64,
( v == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" );
memcpy( iv, aes_test_cfb128_iv, 16 );
memcpy( key, aes_test_cfb128_key[u], 16 + u * 8 );
offset = 0;
mbedtls_aes_setkey_enc( &ctx, key, 128 + u * 64 );
if( v == MBEDTLS_AES_DECRYPT )
{
memcpy( buf, aes_test_cfb128_ct[u], 64 );
mbedtls_aes_crypt_cfb128( &ctx, v, 64, &offset, iv, buf, buf );
if( memcmp( buf, aes_test_cfb128_pt, 64 ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
ret = 1;
goto exit;
}
}
else
{
memcpy( buf, aes_test_cfb128_pt, 64 );
mbedtls_aes_crypt_cfb128( &ctx, v, 64, &offset, iv, buf, buf );
if( memcmp( buf, aes_test_cfb128_ct[u], 64 ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
ret = 1;
goto exit;
}
}
if( verbose != 0 )
mbedtls_printf( "passed\n" );
}
if( verbose != 0 )
mbedtls_printf( "\n" );
#endif /* MBEDTLS_CIPHER_MODE_CFB */
#if defined(MBEDTLS_CIPHER_MODE_CTR)
/*
* CTR mode
*/
for( i = 0; i < 6; i++ )
{
u = i >> 1;
v = i & 1;
if( verbose != 0 )
mbedtls_printf( " AES-CTR-128 (%s): ",
( v == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" );
memcpy( nonce_counter, aes_test_ctr_nonce_counter[u], 16 );
memcpy( key, aes_test_ctr_key[u], 16 );
offset = 0;
mbedtls_aes_setkey_enc( &ctx, key, 128 );
if( v == MBEDTLS_AES_DECRYPT )
{
len = aes_test_ctr_len[u];
memcpy( buf, aes_test_ctr_ct[u], len );
mbedtls_aes_crypt_ctr( &ctx, len, &offset, nonce_counter, stream_block,
buf, buf );
if( memcmp( buf, aes_test_ctr_pt[u], len ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
ret = 1;
goto exit;
}
}
else
{
len = aes_test_ctr_len[u];
memcpy( buf, aes_test_ctr_pt[u], len );
mbedtls_aes_crypt_ctr( &ctx, len, &offset, nonce_counter, stream_block,
buf, buf );
if( memcmp( buf, aes_test_ctr_ct[u], len ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
ret = 1;
goto exit;
}
}
if( verbose != 0 )
mbedtls_printf( "passed\n" );
}
if( verbose != 0 )
mbedtls_printf( "\n" );
#endif /* MBEDTLS_CIPHER_MODE_CTR */
ret = 0;
exit:
mbedtls_aes_free( &ctx );
return( ret );
}
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_AES_C */
/*
* AES-NI support functions
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed 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.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* [AES-WP] http://software.intel.com/en-us/articles/intel-advanced-encryption-standard-aes-instructions-set
* [CLMUL-WP] http://software.intel.com/en-us/articles/intel-carry-less-multiplication-instruction-and-its-usage-for-computing-the-gcm-mode/
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_AESNI_C)
#include "mbedtls/aesni.h"
#include <string.h>
#ifndef asm
#define asm __asm
#endif
#if defined(MBEDTLS_HAVE_X86_64)
/*
* AES-NI support detection routine
*/
int mbedtls_aesni_has_support( unsigned int what )
{
static int done = 0;
static unsigned int c = 0;
if( ! done )
{
asm( "movl $1, %%eax \n\t"
"cpuid \n\t"
: "=c" (c)
:
: "eax", "ebx", "edx" );
done = 1;
}
return( ( c & what ) != 0 );
}
/*
* Binutils needs to be at least 2.19 to support AES-NI instructions.
* Unfortunately, a lot of users have a lower version now (2014-04).
* Emit bytecode directly in order to support "old" version of gas.
*
* Opcodes from the Intel architecture reference manual, vol. 3.
* We always use registers, so we don't need prefixes for memory operands.
* Operand macros are in gas order (src, dst) as opposed to Intel order
* (dst, src) in order to blend better into the surrounding assembly code.
*/
#define AESDEC ".byte 0x66,0x0F,0x38,0xDE,"
#define AESDECLAST ".byte 0x66,0x0F,0x38,0xDF,"
#define AESENC ".byte 0x66,0x0F,0x38,0xDC,"
#define AESENCLAST ".byte 0x66,0x0F,0x38,0xDD,"
#define AESIMC ".byte 0x66,0x0F,0x38,0xDB,"
#define AESKEYGENA ".byte 0x66,0x0F,0x3A,0xDF,"
#define PCLMULQDQ ".byte 0x66,0x0F,0x3A,0x44,"
#define xmm0_xmm0 "0xC0"
#define xmm0_xmm1 "0xC8"
#define xmm0_xmm2 "0xD0"
#define xmm0_xmm3 "0xD8"
#define xmm0_xmm4 "0xE0"
#define xmm1_xmm0 "0xC1"
#define xmm1_xmm2 "0xD1"
/*
* AES-NI AES-ECB block en(de)cryption
*/
int mbedtls_aesni_crypt_ecb( mbedtls_aes_context *ctx,
int mode,
const unsigned char input[16],
unsigned char output[16] )
{
asm( "movdqu (%3), %%xmm0 \n\t" // load input
"movdqu (%1), %%xmm1 \n\t" // load round key 0
"pxor %%xmm1, %%xmm0 \n\t" // round 0
"addq $16, %1 \n\t" // point to next round key
"subl $1, %0 \n\t" // normal rounds = nr - 1
"test %2, %2 \n\t" // mode?
"jz 2f \n\t" // 0 = decrypt
"1: \n\t" // encryption loop
"movdqu (%1), %%xmm1 \n\t" // load round key
AESENC xmm1_xmm0 "\n\t" // do round
"addq $16, %1 \n\t" // point to next round key
"subl $1, %0 \n\t" // loop
"jnz 1b \n\t"
"movdqu (%1), %%xmm1 \n\t" // load round key
AESENCLAST xmm1_xmm0 "\n\t" // last round
"jmp 3f \n\t"
"2: \n\t" // decryption loop
"movdqu (%1), %%xmm1 \n\t"
AESDEC xmm1_xmm0 "\n\t" // do round
"addq $16, %1 \n\t"
"subl $1, %0 \n\t"
"jnz 2b \n\t"
"movdqu (%1), %%xmm1 \n\t" // load round key
AESDECLAST xmm1_xmm0 "\n\t" // last round
"3: \n\t"
"movdqu %%xmm0, (%4) \n\t" // export output
:
: "r" (ctx->nr), "r" (ctx->rk), "r" (mode), "r" (input), "r" (output)
: "memory", "cc", "xmm0", "xmm1" );
return( 0 );
}
/*
* GCM multiplication: c = a times b in GF(2^128)
* Based on [CLMUL-WP] algorithms 1 (with equation 27) and 5.
*/
void mbedtls_aesni_gcm_mult( unsigned char c[16],
const unsigned char a[16],
const unsigned char b[16] )
{
unsigned char aa[16], bb[16], cc[16];
size_t i;
/* The inputs are in big-endian order, so byte-reverse them */
for( i = 0; i < 16; i++ )
{
aa[i] = a[15 - i];
bb[i] = b[15 - i];
}
asm( "movdqu (%0), %%xmm0 \n\t" // a1:a0
"movdqu (%1), %%xmm1 \n\t" // b1:b0
/*
* Caryless multiplication xmm2:xmm1 = xmm0 * xmm1
* using [CLMUL-WP] algorithm 1 (p. 13).
*/
"movdqa %%xmm1, %%xmm2 \n\t" // copy of b1:b0
"movdqa %%xmm1, %%xmm3 \n\t" // same
"movdqa %%xmm1, %%xmm4 \n\t" // same
PCLMULQDQ xmm0_xmm1 ",0x00 \n\t" // a0*b0 = c1:c0
PCLMULQDQ xmm0_xmm2 ",0x11 \n\t" // a1*b1 = d1:d0
PCLMULQDQ xmm0_xmm3 ",0x10 \n\t" // a0*b1 = e1:e0
PCLMULQDQ xmm0_xmm4 ",0x01 \n\t" // a1*b0 = f1:f0
"pxor %%xmm3, %%xmm4 \n\t" // e1+f1:e0+f0
"movdqa %%xmm4, %%xmm3 \n\t" // same
"psrldq $8, %%xmm4 \n\t" // 0:e1+f1
"pslldq $8, %%xmm3 \n\t" // e0+f0:0
"pxor %%xmm4, %%xmm2 \n\t" // d1:d0+e1+f1
"pxor %%xmm3, %%xmm1 \n\t" // c1+e0+f1:c0
/*
* Now shift the result one bit to the left,
* taking advantage of [CLMUL-WP] eq 27 (p. 20)
*/
"movdqa %%xmm1, %%xmm3 \n\t" // r1:r0
"movdqa %%xmm2, %%xmm4 \n\t" // r3:r2
"psllq $1, %%xmm1 \n\t" // r1<<1:r0<<1
"psllq $1, %%xmm2 \n\t" // r3<<1:r2<<1
"psrlq $63, %%xmm3 \n\t" // r1>>63:r0>>63
"psrlq $63, %%xmm4 \n\t" // r3>>63:r2>>63
"movdqa %%xmm3, %%xmm5 \n\t" // r1>>63:r0>>63
"pslldq $8, %%xmm3 \n\t" // r0>>63:0
"pslldq $8, %%xmm4 \n\t" // r2>>63:0
"psrldq $8, %%xmm5 \n\t" // 0:r1>>63
"por %%xmm3, %%xmm1 \n\t" // r1<<1|r0>>63:r0<<1
"por %%xmm4, %%xmm2 \n\t" // r3<<1|r2>>62:r2<<1
"por %%xmm5, %%xmm2 \n\t" // r3<<1|r2>>62:r2<<1|r1>>63
/*
* Now reduce modulo the GCM polynomial x^128 + x^7 + x^2 + x + 1
* using [CLMUL-WP] algorithm 5 (p. 20).
* Currently xmm2:xmm1 holds x3:x2:x1:x0 (already shifted).
*/
/* Step 2 (1) */
"movdqa %%xmm1, %%xmm3 \n\t" // x1:x0
"movdqa %%xmm1, %%xmm4 \n\t" // same
"movdqa %%xmm1, %%xmm5 \n\t" // same
"psllq $63, %%xmm3 \n\t" // x1<<63:x0<<63 = stuff:a
"psllq $62, %%xmm4 \n\t" // x1<<62:x0<<62 = stuff:b
"psllq $57, %%xmm5 \n\t" // x1<<57:x0<<57 = stuff:c
/* Step 2 (2) */
"pxor %%xmm4, %%xmm3 \n\t" // stuff:a+b
"pxor %%xmm5, %%xmm3 \n\t" // stuff:a+b+c
"pslldq $8, %%xmm3 \n\t" // a+b+c:0
"pxor %%xmm3, %%xmm1 \n\t" // x1+a+b+c:x0 = d:x0
/* Steps 3 and 4 */
"movdqa %%xmm1,%%xmm0 \n\t" // d:x0
"movdqa %%xmm1,%%xmm4 \n\t" // same
"movdqa %%xmm1,%%xmm5 \n\t" // same
"psrlq $1, %%xmm0 \n\t" // e1:x0>>1 = e1:e0'
"psrlq $2, %%xmm4 \n\t" // f1:x0>>2 = f1:f0'
"psrlq $7, %%xmm5 \n\t" // g1:x0>>7 = g1:g0'
"pxor %%xmm4, %%xmm0 \n\t" // e1+f1:e0'+f0'
"pxor %%xmm5, %%xmm0 \n\t" // e1+f1+g1:e0'+f0'+g0'
// e0'+f0'+g0' is almost e0+f0+g0, ex\tcept for some missing
// bits carried from d. Now get those\t bits back in.
"movdqa %%xmm1,%%xmm3 \n\t" // d:x0
"movdqa %%xmm1,%%xmm4 \n\t" // same
"movdqa %%xmm1,%%xmm5 \n\t" // same
"psllq $63, %%xmm3 \n\t" // d<<63:stuff
"psllq $62, %%xmm4 \n\t" // d<<62:stuff
"psllq $57, %%xmm5 \n\t" // d<<57:stuff
"pxor %%xmm4, %%xmm3 \n\t" // d<<63+d<<62:stuff
"pxor %%xmm5, %%xmm3 \n\t" // missing bits of d:stuff
"psrldq $8, %%xmm3 \n\t" // 0:missing bits of d
"pxor %%xmm3, %%xmm0 \n\t" // e1+f1+g1:e0+f0+g0
"pxor %%xmm1, %%xmm0 \n\t" // h1:h0
"pxor %%xmm2, %%xmm0 \n\t" // x3+h1:x2+h0
"movdqu %%xmm0, (%2) \n\t" // done
:
: "r" (aa), "r" (bb), "r" (cc)
: "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" );
/* Now byte-reverse the outputs */
for( i = 0; i < 16; i++ )
c[i] = cc[15 - i];
return;
}
/*
* Compute decryption round keys from encryption round keys
*/
void mbedtls_aesni_inverse_key( unsigned char *invkey,
const unsigned char *fwdkey, int nr )
{
unsigned char *ik = invkey;
const unsigned char *fk = fwdkey + 16 * nr;
memcpy( ik, fk, 16 );
for( fk -= 16, ik += 16; fk > fwdkey; fk -= 16, ik += 16 )
asm( "movdqu (%0), %%xmm0 \n\t"
AESIMC xmm0_xmm0 "\n\t"
"movdqu %%xmm0, (%1) \n\t"
:
: "r" (fk), "r" (ik)
: "memory", "xmm0" );
memcpy( ik, fk, 16 );
}
/*
* Key expansion, 128-bit case
*/
static void aesni_setkey_enc_128( unsigned char *rk,
const unsigned char *key )
{
asm( "movdqu (%1), %%xmm0 \n\t" // copy the original key
"movdqu %%xmm0, (%0) \n\t" // as round key 0
"jmp 2f \n\t" // skip auxiliary routine
/*
* Finish generating the next round key.
*
* On entry xmm0 is r3:r2:r1:r0 and xmm1 is X:stuff:stuff:stuff
* with X = rot( sub( r3 ) ) ^ RCON.
*
* On exit, xmm0 is r7:r6:r5:r4
* with r4 = X + r0, r5 = r4 + r1, r6 = r5 + r2, r7 = r6 + r3
* and those are written to the round key buffer.
*/
"1: \n\t"
"pshufd $0xff, %%xmm1, %%xmm1 \n\t" // X:X:X:X
"pxor %%xmm0, %%xmm1 \n\t" // X+r3:X+r2:X+r1:r4
"pslldq $4, %%xmm0 \n\t" // r2:r1:r0:0
"pxor %%xmm0, %%xmm1 \n\t" // X+r3+r2:X+r2+r1:r5:r4
"pslldq $4, %%xmm0 \n\t" // etc
"pxor %%xmm0, %%xmm1 \n\t"
"pslldq $4, %%xmm0 \n\t"
"pxor %%xmm1, %%xmm0 \n\t" // update xmm0 for next time!
"add $16, %0 \n\t" // point to next round key
"movdqu %%xmm0, (%0) \n\t" // write it
"ret \n\t"
/* Main "loop" */
"2: \n\t"
AESKEYGENA xmm0_xmm1 ",0x01 \n\tcall 1b \n\t"
AESKEYGENA xmm0_xmm1 ",0x02 \n\tcall 1b \n\t"
AESKEYGENA xmm0_xmm1 ",0x04 \n\tcall 1b \n\t"
AESKEYGENA xmm0_xmm1 ",0x08 \n\tcall 1b \n\t"
AESKEYGENA xmm0_xmm1 ",0x10 \n\tcall 1b \n\t"
AESKEYGENA xmm0_xmm1 ",0x20 \n\tcall 1b \n\t"
AESKEYGENA xmm0_xmm1 ",0x40 \n\tcall 1b \n\t"
AESKEYGENA xmm0_xmm1 ",0x80 \n\tcall 1b \n\t"
AESKEYGENA xmm0_xmm1 ",0x1B \n\tcall 1b \n\t"
AESKEYGENA xmm0_xmm1 ",0x36 \n\tcall 1b \n\t"
:
: "r" (rk), "r" (key)
: "memory", "cc", "0" );
}
/*
* Key expansion, 192-bit case
*/
static void aesni_setkey_enc_192( unsigned char *rk,
const unsigned char *key )
{
asm( "movdqu (%1), %%xmm0 \n\t" // copy original round key
"movdqu %%xmm0, (%0) \n\t"
"add $16, %0 \n\t"
"movq 16(%1), %%xmm1 \n\t"
"movq %%xmm1, (%0) \n\t"
"add $8, %0 \n\t"
"jmp 2f \n\t" // skip auxiliary routine
/*
* Finish generating the next 6 quarter-keys.
*
* On entry xmm0 is r3:r2:r1:r0, xmm1 is stuff:stuff:r5:r4
* and xmm2 is stuff:stuff:X:stuff with X = rot( sub( r3 ) ) ^ RCON.
*
* On exit, xmm0 is r9:r8:r7:r6 and xmm1 is stuff:stuff:r11:r10
* and those are written to the round key buffer.
*/
"1: \n\t"
"pshufd $0x55, %%xmm2, %%xmm2 \n\t" // X:X:X:X
"pxor %%xmm0, %%xmm2 \n\t" // X+r3:X+r2:X+r1:r4
"pslldq $4, %%xmm0 \n\t" // etc
"pxor %%xmm0, %%xmm2 \n\t"
"pslldq $4, %%xmm0 \n\t"
"pxor %%xmm0, %%xmm2 \n\t"
"pslldq $4, %%xmm0 \n\t"
"pxor %%xmm2, %%xmm0 \n\t" // update xmm0 = r9:r8:r7:r6
"movdqu %%xmm0, (%0) \n\t"
"add $16, %0 \n\t"
"pshufd $0xff, %%xmm0, %%xmm2 \n\t" // r9:r9:r9:r9
"pxor %%xmm1, %%xmm2 \n\t" // stuff:stuff:r9+r5:r10
"pslldq $4, %%xmm1 \n\t" // r2:r1:r0:0
"pxor %%xmm2, %%xmm1 \n\t" // xmm1 = stuff:stuff:r11:r10
"movq %%xmm1, (%0) \n\t"
"add $8, %0 \n\t"
"ret \n\t"
"2: \n\t"
AESKEYGENA xmm1_xmm2 ",0x01 \n\tcall 1b \n\t"
AESKEYGENA xmm1_xmm2 ",0x02 \n\tcall 1b \n\t"
AESKEYGENA xmm1_xmm2 ",0x04 \n\tcall 1b \n\t"
AESKEYGENA xmm1_xmm2 ",0x08 \n\tcall 1b \n\t"
AESKEYGENA xmm1_xmm2 ",0x10 \n\tcall 1b \n\t"
AESKEYGENA xmm1_xmm2 ",0x20 \n\tcall 1b \n\t"
AESKEYGENA xmm1_xmm2 ",0x40 \n\tcall 1b \n\t"
AESKEYGENA xmm1_xmm2 ",0x80 \n\tcall 1b \n\t"
:
: "r" (rk), "r" (key)
: "memory", "cc", "0" );
}
/*
* Key expansion, 256-bit case
*/
static void aesni_setkey_enc_256( unsigned char *rk,
const unsigned char *key )
{
asm( "movdqu (%1), %%xmm0 \n\t"
"movdqu %%xmm0, (%0) \n\t"
"add $16, %0 \n\t"
"movdqu 16(%1), %%xmm1 \n\t"
"movdqu %%xmm1, (%0) \n\t"
"jmp 2f \n\t" // skip auxiliary routine
/*
* Finish generating the next two round keys.
*
* On entry xmm0 is r3:r2:r1:r0, xmm1 is r7:r6:r5:r4 and
* xmm2 is X:stuff:stuff:stuff with X = rot( sub( r7 )) ^ RCON
*
* On exit, xmm0 is r11:r10:r9:r8 and xmm1 is r15:r14:r13:r12
* and those have been written to the output buffer.
*/
"1: \n\t"
"pshufd $0xff, %%xmm2, %%xmm2 \n\t"
"pxor %%xmm0, %%xmm2 \n\t"
"pslldq $4, %%xmm0 \n\t"
"pxor %%xmm0, %%xmm2 \n\t"
"pslldq $4, %%xmm0 \n\t"
"pxor %%xmm0, %%xmm2 \n\t"
"pslldq $4, %%xmm0 \n\t"
"pxor %%xmm2, %%xmm0 \n\t"
"add $16, %0 \n\t"
"movdqu %%xmm0, (%0) \n\t"
/* Set xmm2 to stuff:Y:stuff:stuff with Y = subword( r11 )
* and proceed to generate next round key from there */
AESKEYGENA xmm0_xmm2 ",0x00 \n\t"
"pshufd $0xaa, %%xmm2, %%xmm2 \n\t"
"pxor %%xmm1, %%xmm2 \n\t"
"pslldq $4, %%xmm1 \n\t"
"pxor %%xmm1, %%xmm2 \n\t"
"pslldq $4, %%xmm1 \n\t"
"pxor %%xmm1, %%xmm2 \n\t"
"pslldq $4, %%xmm1 \n\t"
"pxor %%xmm2, %%xmm1 \n\t"
"add $16, %0 \n\t"
"movdqu %%xmm1, (%0) \n\t"
"ret \n\t"
/*
* Main "loop" - Generating one more key than necessary,
* see definition of mbedtls_aes_context.buf
*/
"2: \n\t"
AESKEYGENA xmm1_xmm2 ",0x01 \n\tcall 1b \n\t"
AESKEYGENA xmm1_xmm2 ",0x02 \n\tcall 1b \n\t"
AESKEYGENA xmm1_xmm2 ",0x04 \n\tcall 1b \n\t"
AESKEYGENA xmm1_xmm2 ",0x08 \n\tcall 1b \n\t"
AESKEYGENA xmm1_xmm2 ",0x10 \n\tcall 1b \n\t"
AESKEYGENA xmm1_xmm2 ",0x20 \n\tcall 1b \n\t"
AESKEYGENA xmm1_xmm2 ",0x40 \n\tcall 1b \n\t"
:
: "r" (rk), "r" (key)
: "memory", "cc", "0" );
}
/*
* Key expansion, wrapper
*/
int mbedtls_aesni_setkey_enc( unsigned char *rk,
const unsigned char *key,
size_t bits )
{
switch( bits )
{
case 128: aesni_setkey_enc_128( rk, key ); break;
case 192: aesni_setkey_enc_192( rk, key ); break;
case 256: aesni_setkey_enc_256( rk, key ); break;
default : return( MBEDTLS_ERR_AES_INVALID_KEY_LENGTH );
}
return( 0 );
}
#endif /* MBEDTLS_HAVE_X86_64 */
#endif /* MBEDTLS_AESNI_C */
/*
* An implementation of the ARCFOUR algorithm
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed 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.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* The ARCFOUR algorithm was publicly disclosed on 94/09.
*
* http://groups.google.com/group/sci.crypt/msg/10a300c9d21afca0
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_ARC4_C)
#include "mbedtls/arc4.h"
#include <string.h>
#if defined(MBEDTLS_SELF_TEST)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST */
#if !defined(MBEDTLS_ARC4_ALT)
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n ) {
volatile unsigned char *p = v; while( n-- ) *p++ = 0;
}
void mbedtls_arc4_init( mbedtls_arc4_context *ctx )
{
memset( ctx, 0, sizeof( mbedtls_arc4_context ) );
}
void mbedtls_arc4_free( mbedtls_arc4_context *ctx )
{
if( ctx == NULL )
return;
mbedtls_zeroize( ctx, sizeof( mbedtls_arc4_context ) );
}
/*
* ARC4 key schedule
*/
void mbedtls_arc4_setup( mbedtls_arc4_context *ctx, const unsigned char *key,
unsigned int keylen )
{
int i, j, a;
unsigned int k;
unsigned char *m;
ctx->x = 0;
ctx->y = 0;
m = ctx->m;
for( i = 0; i < 256; i++ )
m[i] = (unsigned char) i;
j = k = 0;
for( i = 0; i < 256; i++, k++ )
{
if( k >= keylen ) k = 0;
a = m[i];
j = ( j + a + key[k] ) & 0xFF;
m[i] = m[j];
m[j] = (unsigned char) a;
}
}
/*
* ARC4 cipher function
*/
int mbedtls_arc4_crypt( mbedtls_arc4_context *ctx, size_t length, const unsigned char *input,
unsigned char *output )
{
int x, y, a, b;
size_t i;
unsigned char *m;
x = ctx->x;
y = ctx->y;
m = ctx->m;
for( i = 0; i < length; i++ )
{
x = ( x + 1 ) & 0xFF; a = m[x];
y = ( y + a ) & 0xFF; b = m[y];
m[x] = (unsigned char) b;
m[y] = (unsigned char) a;
output[i] = (unsigned char)
( input[i] ^ m[(unsigned char)( a + b )] );
}
ctx->x = x;
ctx->y = y;
return( 0 );
}
#endif /* !MBEDTLS_ARC4_ALT */
#if defined(MBEDTLS_SELF_TEST)
/*
* ARC4 tests vectors as posted by Eric Rescorla in sep. 1994:
*
* http://groups.google.com/group/comp.security.misc/msg/10a300c9d21afca0
*/
static const unsigned char arc4_test_key[3][8] =
{
{ 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF },
{ 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
};
static const unsigned char arc4_test_pt[3][8] =
{
{ 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
};
static const unsigned char arc4_test_ct[3][8] =
{
{ 0x75, 0xB7, 0x87, 0x80, 0x99, 0xE0, 0xC5, 0x96 },
{ 0x74, 0x94, 0xC2, 0xE7, 0x10, 0x4B, 0x08, 0x79 },
{ 0xDE, 0x18, 0x89, 0x41, 0xA3, 0x37, 0x5D, 0x3A }
};
/*
* Checkup routine
*/
int mbedtls_arc4_self_test( int verbose )
{
int i, ret = 0;
unsigned char ibuf[8];
unsigned char obuf[8];
mbedtls_arc4_context ctx;
mbedtls_arc4_init( &ctx );
for( i = 0; i < 3; i++ )
{
if( verbose != 0 )
mbedtls_printf( " ARC4 test #%d: ", i + 1 );
memcpy( ibuf, arc4_test_pt[i], 8 );
mbedtls_arc4_setup( &ctx, arc4_test_key[i], 8 );
mbedtls_arc4_crypt( &ctx, 8, ibuf, obuf );
if( memcmp( obuf, arc4_test_ct[i], 8 ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
ret = 1;
goto exit;
}
if( verbose != 0 )
mbedtls_printf( "passed\n" );
}
if( verbose != 0 )
mbedtls_printf( "\n" );
exit:
mbedtls_arc4_free( &ctx );
return( ret );
}
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_ARC4_C */
/*
* Generic ASN.1 parsing
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed 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.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_ASN1_PARSE_C)
#include "mbedtls/asn1.h"
#include <string.h>
#if defined(MBEDTLS_BIGNUM_C)
#include "mbedtls/bignum.h"
#endif
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdlib.h>
#define mbedtls_calloc calloc
#define mbedtls_free free
#endif
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n ) {
volatile unsigned char *p = v; while( n-- ) *p++ = 0;
}
/*
* ASN.1 DER decoding routines
*/
int mbedtls_asn1_get_len( unsigned char **p,
const unsigned char *end,
size_t *len )
{
if( ( end - *p ) < 1 )
return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
if( ( **p & 0x80 ) == 0 )
*len = *(*p)++;
else
{
switch( **p & 0x7F )
{
case 1:
if( ( end - *p ) < 2 )
return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
*len = (*p)[1];
(*p) += 2;
break;
case 2:
if( ( end - *p ) < 3 )
return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
*len = ( (size_t)(*p)[1] << 8 ) | (*p)[2];
(*p) += 3;
break;
case 3:
if( ( end - *p ) < 4 )
return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
*len = ( (size_t)(*p)[1] << 16 ) |
( (size_t)(*p)[2] << 8 ) | (*p)[3];
(*p) += 4;
break;
case 4:
if( ( end - *p ) < 5 )
return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
*len = ( (size_t)(*p)[1] << 24 ) | ( (size_t)(*p)[2] << 16 ) |
( (size_t)(*p)[3] << 8 ) | (*p)[4];
(*p) += 5;
break;
default:
return( MBEDTLS_ERR_ASN1_INVALID_LENGTH );
}
}
if( *len > (size_t) ( end - *p ) )
return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
return( 0 );
}
int mbedtls_asn1_get_tag( unsigned char **p,
const unsigned char *end,
size_t *len, int tag )
{
if( ( end - *p ) < 1 )
return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
if( **p != tag )
return( MBEDTLS_ERR_ASN1_UNEXPECTED_TAG );
(*p)++;
return( mbedtls_asn1_get_len( p, end, len ) );
}
int mbedtls_asn1_get_bool( unsigned char **p,
const unsigned char *end,
int *val )
{
int ret;
size_t len;
if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_BOOLEAN ) ) != 0 )
return( ret );
if( len != 1 )
return( MBEDTLS_ERR_ASN1_INVALID_LENGTH );
*val = ( **p != 0 ) ? 1 : 0;
(*p)++;
return( 0 );
}
int mbedtls_asn1_get_int( unsigned char **p,
const unsigned char *end,
int *val )
{
int ret;
size_t len;
if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ) ) != 0 )
return( ret );
if( len > sizeof( int ) || ( **p & 0x80 ) != 0 )
return( MBEDTLS_ERR_ASN1_INVALID_LENGTH );
*val = 0;
while( len-- > 0 )
{
*val = ( *val << 8 ) | **p;
(*p)++;
}
return( 0 );
}
#if defined(MBEDTLS_BIGNUM_C)
int mbedtls_asn1_get_mpi( unsigned char **p,
const unsigned char *end,
mbedtls_mpi *X )
{
int ret;
size_t len;
if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ) ) != 0 )
return( ret );
ret = mbedtls_mpi_read_binary( X, *p, len );
*p += len;
return( ret );
}
#endif /* MBEDTLS_BIGNUM_C */
int mbedtls_asn1_get_bitstring( unsigned char **p, const unsigned char *end,
mbedtls_asn1_bitstring *bs)
{
int ret;
/* Certificate type is a single byte bitstring */
if( ( ret = mbedtls_asn1_get_tag( p, end, &bs->len, MBEDTLS_ASN1_BIT_STRING ) ) != 0 )
return( ret );
/* Check length, subtract one for actual bit string length */
if( bs->len < 1 )
return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
bs->len -= 1;
/* Get number of unused bits, ensure unused bits <= 7 */
bs->unused_bits = **p;
if( bs->unused_bits > 7 )
return( MBEDTLS_ERR_ASN1_INVALID_LENGTH );
(*p)++;
/* Get actual bitstring */
bs->p = *p;
*p += bs->len;
if( *p != end )
return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
return( 0 );
}
/*
* Get a bit string without unused bits
*/
int mbedtls_asn1_get_bitstring_null( unsigned char **p, const unsigned char *end,
size_t *len )
{
int ret;
if( ( ret = mbedtls_asn1_get_tag( p, end, len, MBEDTLS_ASN1_BIT_STRING ) ) != 0 )
return( ret );
if( (*len)-- < 2 || *(*p)++ != 0 )
return( MBEDTLS_ERR_ASN1_INVALID_DATA );
return( 0 );
}
/*
* Parses and splits an ASN.1 "SEQUENCE OF <tag>"
*/
int mbedtls_asn1_get_sequence_of( unsigned char **p,
const unsigned char *end,
mbedtls_asn1_sequence *cur,
int tag)
{
int ret;
size_t len;
mbedtls_asn1_buf *buf;
/* Get main sequence tag */
if( ( ret = mbedtls_asn1_get_tag( p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
return( ret );
if( *p + len != end )
return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
while( *p < end )
{
buf = &(cur->buf);
buf->tag = **p;
if( ( ret = mbedtls_asn1_get_tag( p, end, &buf->len, tag ) ) != 0 )
return( ret );
buf->p = *p;
*p += buf->len;
/* Allocate and assign next pointer */
if( *p < end )
{
cur->next = mbedtls_calloc( 1, sizeof( mbedtls_asn1_sequence ) );
if( cur->next == NULL )
return( MBEDTLS_ERR_ASN1_ALLOC_FAILED );
cur = cur->next;
}
}
/* Set final sequence entry's next pointer to NULL */
cur->next = NULL;
if( *p != end )
return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
return( 0 );
}
int mbedtls_asn1_get_alg( unsigned char **p,
const unsigned char *end,
mbedtls_asn1_buf *alg, mbedtls_asn1_buf *params )
{
int ret;
size_t len;
if( ( ret = mbedtls_asn1_get_tag( p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
return( ret );
if( ( end - *p ) < 1 )
return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
alg->tag = **p;
end = *p + len;
if( ( ret = mbedtls_asn1_get_tag( p, end, &alg->len, MBEDTLS_ASN1_OID ) ) != 0 )
return( ret );
alg->p = *p;
*p += alg->len;
if( *p == end )
{
mbedtls_zeroize( params, sizeof(mbedtls_asn1_buf) );
return( 0 );
}
params->tag = **p;
(*p)++;
if( ( ret = mbedtls_asn1_get_len( p, end, &params->len ) ) != 0 )
return( ret );
params->p = *p;
*p += params->len;
if( *p != end )
return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
return( 0 );
}
int mbedtls_asn1_get_alg_null( unsigned char **p,
const unsigned char *end,
mbedtls_asn1_buf *alg )
{
int ret;
mbedtls_asn1_buf params;
memset( &params, 0, sizeof(mbedtls_asn1_buf) );
if( ( ret = mbedtls_asn1_get_alg( p, end, alg, &params ) ) != 0 )
return( ret );
if( ( params.tag != MBEDTLS_ASN1_NULL && params.tag != 0 ) || params.len != 0 )
return( MBEDTLS_ERR_ASN1_INVALID_DATA );
return( 0 );
}
void mbedtls_asn1_free_named_data( mbedtls_asn1_named_data *cur )
{
if( cur == NULL )
return;
mbedtls_free( cur->oid.p );
mbedtls_free( cur->val.p );
mbedtls_zeroize( cur, sizeof( mbedtls_asn1_named_data ) );
}
void mbedtls_asn1_free_named_data_list( mbedtls_asn1_named_data **head )
{
mbedtls_asn1_named_data *cur;
while( ( cur = *head ) != NULL )
{
*head = cur->next;
mbedtls_asn1_free_named_data( cur );
mbedtls_free( cur );
}
}
mbedtls_asn1_named_data *mbedtls_asn1_find_named_data( mbedtls_asn1_named_data *list,
const char *oid, size_t len )
{
while( list != NULL )
{
if( list->oid.len == len &&
memcmp( list->oid.p, oid, len ) == 0 )
{
break;
}
list = list->next;
}
return( list );
}
#endif /* MBEDTLS_ASN1_PARSE_C */
/*
* ASN.1 buffer writing functionality
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed 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.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_ASN1_WRITE_C)
#include "mbedtls/asn1write.h"
#include <string.h>
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdlib.h>
#define mbedtls_calloc calloc
#define mbedtls_free free
#endif
int mbedtls_asn1_write_len( unsigned char **p, unsigned char *start, size_t len )
{
if( len < 0x80 )
{
if( *p - start < 1 )
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
*--(*p) = (unsigned char) len;
return( 1 );
}
if( len <= 0xFF )
{
if( *p - start < 2 )
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
*--(*p) = (unsigned char) len;
*--(*p) = 0x81;
return( 2 );
}
if( *p - start < 3 )
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
// We assume we never have lengths larger than 65535 bytes
//
*--(*p) = len % 256;
*--(*p) = ( len / 256 ) % 256;
*--(*p) = 0x82;
return( 3 );
}
int mbedtls_asn1_write_tag( unsigned char **p, unsigned char *start, unsigned char tag )
{
if( *p - start < 1 )
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
*--(*p) = tag;
return( 1 );
}
int mbedtls_asn1_write_raw_buffer( unsigned char **p, unsigned char *start,
const unsigned char *buf, size_t size )
{
size_t len = 0;
if( *p < start || (size_t)( *p - start ) < size )
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
len = size;
(*p) -= len;
memcpy( *p, buf, len );
return( (int) len );
}
#if defined(MBEDTLS_BIGNUM_C)
int mbedtls_asn1_write_mpi( unsigned char **p, unsigned char *start, const mbedtls_mpi *X )
{
int ret;
size_t len = 0;
// Write the MPI
//
len = mbedtls_mpi_size( X );
if( *p < start || (size_t)( *p - start ) < len )
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
(*p) -= len;
MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( X, *p, len ) );
// DER format assumes 2s complement for numbers, so the leftmost bit
// should be 0 for positive numbers and 1 for negative numbers.
//
if( X->s ==1 && **p & 0x80 )
{
if( *p - start < 1 )
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
*--(*p) = 0x00;
len += 1;
}
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_INTEGER ) );
ret = (int) len;
cleanup:
return( ret );
}
#endif /* MBEDTLS_BIGNUM_C */
int mbedtls_asn1_write_null( unsigned char **p, unsigned char *start )
{
int ret;
size_t len = 0;
// Write NULL
//
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, 0) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_NULL ) );
return( (int) len );
}
int mbedtls_asn1_write_oid( unsigned char **p, unsigned char *start,
const char *oid, size_t oid_len )
{
int ret;
size_t len = 0;
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start,
(const unsigned char *) oid, oid_len ) );
MBEDTLS_ASN1_CHK_ADD( len , mbedtls_asn1_write_len( p, start, len ) );
MBEDTLS_ASN1_CHK_ADD( len , mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_OID ) );
return( (int) len );
}
int mbedtls_asn1_write_algorithm_identifier( unsigned char **p, unsigned char *start,
const char *oid, size_t oid_len,
size_t par_len )
{
int ret;
size_t len = 0;
if( par_len == 0 )
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_null( p, start ) );
else
len += par_len;
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_oid( p, start, oid, oid_len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) );
return( (int) len );
}
int mbedtls_asn1_write_bool( unsigned char **p, unsigned char *start, int boolean )
{
int ret;
size_t len = 0;
if( *p - start < 1 )
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
*--(*p) = (boolean) ? 255 : 0;
len++;
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_BOOLEAN ) );
return( (int) len );
}
int mbedtls_asn1_write_int( unsigned char **p, unsigned char *start, int val )
{
int ret;
size_t len = 0;
// TODO negative values and values larger than 128
// DER format assumes 2s complement for numbers, so the leftmost bit
// should be 0 for positive numbers and 1 for negative numbers.
//
if( *p - start < 1 )
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
len += 1;
*--(*p) = val;
if( val > 0 && **p & 0x80 )
{
if( *p - start < 1 )
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
*--(*p) = 0x00;
len += 1;
}
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_INTEGER ) );
return( (int) len );
}
int mbedtls_asn1_write_printable_string( unsigned char **p, unsigned char *start,
const char *text, size_t text_len )
{
int ret;
size_t len = 0;
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start,
(const unsigned char *) text, text_len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_PRINTABLE_STRING ) );
return( (int) len );
}
int mbedtls_asn1_write_ia5_string( unsigned char **p, unsigned char *start,
const char *text, size_t text_len )
{
int ret;
size_t len = 0;
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start,
(const unsigned char *) text, text_len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_IA5_STRING ) );
return( (int) len );
}
int mbedtls_asn1_write_bitstring( unsigned char **p, unsigned char *start,
const unsigned char *buf, size_t bits )
{
int ret;
size_t len = 0, size;
size = ( bits / 8 ) + ( ( bits % 8 ) ? 1 : 0 );
// Calculate byte length
//
if( *p < start || (size_t)( *p - start ) < size + 1 )
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
len = size + 1;
(*p) -= size;
memcpy( *p, buf, size );
// Write unused bits
//
*--(*p) = (unsigned char) (size * 8 - bits);
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_BIT_STRING ) );
return( (int) len );
}
int mbedtls_asn1_write_octet_string( unsigned char **p, unsigned char *start,
const unsigned char *buf, size_t size )
{
int ret;
size_t len = 0;
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, buf, size ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_OCTET_STRING ) );
return( (int) len );
}
mbedtls_asn1_named_data *mbedtls_asn1_store_named_data( mbedtls_asn1_named_data **head,
const char *oid, size_t oid_len,
const unsigned char *val,
size_t val_len )
{
mbedtls_asn1_named_data *cur;
if( ( cur = mbedtls_asn1_find_named_data( *head, oid, oid_len ) ) == NULL )
{
// Add new entry if not present yet based on OID
//
if( ( cur = mbedtls_calloc( 1, sizeof(mbedtls_asn1_named_data) ) ) == NULL )
return( NULL );
cur->oid.len = oid_len;
cur->oid.p = mbedtls_calloc( 1, oid_len );
if( cur->oid.p == NULL )
{
mbedtls_free( cur );
return( NULL );
}
memcpy( cur->oid.p, oid, oid_len );
cur->val.len = val_len;
cur->val.p = mbedtls_calloc( 1, val_len );
if( cur->val.p == NULL )
{
mbedtls_free( cur->oid.p );
mbedtls_free( cur );
return( NULL );
}
cur->next = *head;
*head = cur;
}
else if( cur->val.len < val_len )
{
/*
* Enlarge existing value buffer if needed
* Preserve old data until the allocation succeeded, to leave list in
* a consistent state in case allocation fails.
*/
void *p = mbedtls_calloc( 1, val_len );
if( p == NULL )
return( NULL );
mbedtls_free( cur->val.p );
cur->val.p = p;
cur->val.len = val_len;
}
if( val != NULL )
memcpy( cur->val.p, val, val_len );
return( cur );
}
#endif /* MBEDTLS_ASN1_WRITE_C */
/*
* RFC 1521 base64 encoding/decoding
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed 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.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_BASE64_C)
#include "mbedtls/base64.h"
#include <stdint.h>
#if defined(MBEDTLS_SELF_TEST)
#include <string.h>
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST */
static const unsigned char base64_enc_map[64] ICACHE_RODATA_ATTR =
{
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '+', '/'
};
static const unsigned char base64_dec_map[128] ICACHE_RODATA_ATTR =
{
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 62, 127, 127, 127, 63, 52, 53,
54, 55, 56, 57, 58, 59, 60, 61, 127, 127,
127, 64, 127, 127, 127, 0, 1, 2, 3, 4,
5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 127, 127, 127, 127, 127, 127, 26, 27, 28,
29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, 127, 127, 127, 127, 127
};
#define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
/*
* Encode a buffer into base64 format
*/
int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
const unsigned char *src, size_t slen )
{
size_t i, n;
int C1, C2, C3;
unsigned char *p;
if( slen == 0 )
{
*olen = 0;
return( 0 );
}
n = slen / 3 + ( slen % 3 != 0 );
if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
{
*olen = BASE64_SIZE_T_MAX;
return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
}
n *= 4;
if( dlen < n + 1 )
{
*olen = n + 1;
return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
}
n = ( slen / 3 ) * 3;
for( i = 0, p = dst; i < n; i += 3 )
{
C1 = *src++;
C2 = *src++;
C3 = *src++;
*p++ = system_get_data_of_array_8(base64_enc_map, (C1 >> 2) & 0x3F);
*p++ = system_get_data_of_array_8(base64_enc_map, (((C1 & 3) << 4) + (C2 >> 4)) & 0x3F);
*p++ = system_get_data_of_array_8(base64_enc_map, (((C2 & 15) << 2) + (C3 >> 6)) & 0x3F);
*p++ = system_get_data_of_array_8(base64_enc_map, C3 & 0x3F);
}
if( i < slen )
{
C1 = *src++;
C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
*p++ = system_get_data_of_array_8(base64_enc_map, (C1 >> 2) & 0x3F);
*p++ = system_get_data_of_array_8(base64_enc_map, (((C1 & 3) << 4) + (C2 >> 4)) & 0x3F);
if( ( i + 1 ) < slen )
*p++ = system_get_data_of_array_8(base64_enc_map, ((C2 & 15) << 2) & 0x3F);
else *p++ = '=';
*p++ = '=';
}
*olen = p - dst;
*p = 0;
return( 0 );
}
/*
* Decode a base64-formatted buffer
*/
int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
const unsigned char *src, size_t slen )
{
size_t i, n;
uint32_t j, x;
unsigned char *p;
/* First pass: check for validity and get output length */
for( i = n = j = 0; i < slen; i++ )
{
/* Skip spaces before checking for EOL */
x = 0;
while( i < slen && src[i] == ' ' )
{
++i;
++x;
}
/* Spaces at end of buffer are OK */
if( i == slen )
break;
if( ( slen - i ) >= 2 &&
src[i] == '\r' && src[i + 1] == '\n' )
continue;
if( src[i] == '\n' )
continue;
/* Space inside a line is an error */
if( x != 0 )
return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
if( src[i] == '=' && ++j > 2 )
return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
if( src[i] > 127 || system_get_data_of_array_8(base64_dec_map, src[i]) == 127 )
return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
if( system_get_data_of_array_8(base64_dec_map, src[i]) < 64 && j != 0 )
return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
n++;
}
if( n == 0 )
{
*olen = 0;
return( 0 );
}
n = ( ( n * 6 ) + 7 ) >> 3;
n -= j;
if( dst == NULL || dlen < n )
{
*olen = n;
return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
}
for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
{
if( *src == '\r' || *src == '\n' || *src == ' ' )
continue;
j -= ( system_get_data_of_array_8(base64_dec_map, *src) == 64 );
x = ( x << 6 ) | ( system_get_data_of_array_8(base64_dec_map, *src) & 0x3F );
if( ++n == 4 )
{
n = 0;
if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
if( j > 1 ) *p++ = (unsigned char)( x >> 8 );
if( j > 2 ) *p++ = (unsigned char)( x );
}
}
*olen = p - dst;
return( 0 );
}
#if defined(MBEDTLS_SELF_TEST)
static const unsigned char base64_test_dec[64] =
{
0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
};
static const unsigned char base64_test_enc[] =
"JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
"swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
/*
* Checkup routine
*/
int mbedtls_base64_self_test( int verbose )
{
size_t len;
const unsigned char *src;
unsigned char buffer[128];
if( verbose != 0 )
mbedtls_printf( " Base64 encoding test: " );
src = base64_test_dec;
if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
memcmp( base64_test_enc, buffer, 88 ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
return( 1 );
}
if( verbose != 0 )
mbedtls_printf( "passed\n Base64 decoding test: " );
src = base64_test_enc;
if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
memcmp( base64_test_dec, buffer, 64 ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
return( 1 );
}
if( verbose != 0 )
mbedtls_printf( "passed\n\n" );
return( 0 );
}
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_BASE64_C */
/*
* Multi-precision integer library
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed 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.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* The following sources were referenced in the design of this Multi-precision
* Integer library:
*
* [1] Handbook of Applied Cryptography - 1997
* Menezes, van Oorschot and Vanstone
*
* [2] Multi-Precision Math
* Tom St Denis
* https://github.com/libtom/libtommath/blob/develop/tommath.pdf
*
* [3] GNU Multi-Precision Arithmetic Library
* https://gmplib.org/manual/index.html
*
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_BIGNUM_C)
#include "c_types.h"
#include "mbedtls/bignum.h"
#include "mbedtls/bn_mul.h"
#include <string.h>
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#include <stdlib.h>
#define mbedtls_printf printf
#define mbedtls_calloc calloc
#define mbedtls_free free
#endif
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n ) {
volatile unsigned char *p = v; while( n-- ) *p++ = 0;
}
#define ciL (sizeof(mbedtls_mpi_uint)) /* chars in limb */
#define biL (ciL << 3) /* bits in limb */
#define biH (ciL << 2) /* half limb size */
#define MPI_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
/*
* Convert between bits/chars and number of limbs
* Divide first in order to avoid potential overflows
*/
#define BITS_TO_LIMBS(i) ( (i) / biL + ( (i) % biL != 0 ) )
#define CHARS_TO_LIMBS(i) ( (i) / ciL + ( (i) % ciL != 0 ) )
/*
* Initialize one MPI
*/
void mbedtls_mpi_init( mbedtls_mpi *X )
{
if( X == NULL )
return;
X->s = 1;
X->n = 0;
X->p = NULL;
}
/*
* Unallocate one MPI
*/
void mbedtls_mpi_free( mbedtls_mpi *X )
{
if( X == NULL )
return;
if( X->p != NULL )
{
mbedtls_zeroize( X->p, X->n * ciL );
mbedtls_free( X->p );
}
X->s = 1;
X->n = 0;
X->p = NULL;
}
/*
* Enlarge to the specified number of limbs
*/
int mbedtls_mpi_grow( mbedtls_mpi *X, size_t nblimbs )
{
mbedtls_mpi_uint *p;
if( nblimbs > MBEDTLS_MPI_MAX_LIMBS )
return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
if( X->n < nblimbs )
{
if( ( p = mbedtls_calloc( nblimbs, ciL ) ) == NULL )
return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
if( X->p != NULL )
{
memcpy( p, X->p, X->n * ciL );
mbedtls_zeroize( X->p, X->n * ciL );
mbedtls_free( X->p );
}
X->n = nblimbs;
X->p = p;
}
return( 0 );
}
/*
* Resize down as much as possible,
* while keeping at least the specified number of limbs
*/
int mbedtls_mpi_shrink( mbedtls_mpi *X, size_t nblimbs )
{
mbedtls_mpi_uint *p;
size_t i;
/* Actually resize up in this case */
if( X->n <= nblimbs )
return( mbedtls_mpi_grow( X, nblimbs ) );
for( i = X->n - 1; i > 0; i-- )
if( X->p[i] != 0 )
break;
i++;
if( i < nblimbs )
i = nblimbs;
if( ( p = mbedtls_calloc( i, ciL ) ) == NULL )
return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
if( X->p != NULL )
{
memcpy( p, X->p, i * ciL );
mbedtls_zeroize( X->p, X->n * ciL );
mbedtls_free( X->p );
}
X->n = i;
X->p = p;
return( 0 );
}
/*
* Copy the contents of Y into X
*/
int mbedtls_mpi_copy( mbedtls_mpi *X, const mbedtls_mpi *Y )
{
int ret;
size_t i;
if( X == Y )
return( 0 );
if( Y->p == NULL )
{
mbedtls_mpi_free( X );
return( 0 );
}
for( i = Y->n - 1; i > 0; i-- )
if( Y->p[i] != 0 )
break;
i++;
X->s = Y->s;
MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i ) );
memset( X->p, 0, X->n * ciL );
memcpy( X->p, Y->p, i * ciL );
cleanup:
return( ret );
}
/*
* Swap the contents of X and Y
*/
void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y )
{
mbedtls_mpi T;
memcpy( &T, X, sizeof( mbedtls_mpi ) );
memcpy( X, Y, sizeof( mbedtls_mpi ) );
memcpy( Y, &T, sizeof( mbedtls_mpi ) );
}
/*
* Conditionally assign X = Y, without leaking information
* about whether the assignment was made or not.
* (Leaking information about the respective sizes of X and Y is ok however.)
*/
int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned char assign )
{
int ret = 0;
size_t i;
/* make sure assign is 0 or 1 in a time-constant manner */
assign = (assign | (unsigned char)-assign) >> 7;
MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) );
X->s = X->s * ( 1 - assign ) + Y->s * assign;
for( i = 0; i < Y->n; i++ )
X->p[i] = X->p[i] * ( 1 - assign ) + Y->p[i] * assign;
for( ; i < X->n; i++ )
X->p[i] *= ( 1 - assign );
cleanup:
return( ret );
}
/*
* Conditionally swap X and Y, without leaking information
* about whether the swap was made or not.
* Here it is not ok to simply swap the pointers, which whould lead to
* different memory access patterns when X and Y are used afterwards.
*/
int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, mbedtls_mpi *Y, unsigned char swap )
{
int ret, s;
size_t i;
mbedtls_mpi_uint tmp;
if( X == Y )
return( 0 );
/* make sure swap is 0 or 1 in a time-constant manner */
swap = (swap | (unsigned char)-swap) >> 7;
MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_grow( Y, X->n ) );
s = X->s;
X->s = X->s * ( 1 - swap ) + Y->s * swap;
Y->s = Y->s * ( 1 - swap ) + s * swap;
for( i = 0; i < X->n; i++ )
{
tmp = X->p[i];
X->p[i] = X->p[i] * ( 1 - swap ) + Y->p[i] * swap;
Y->p[i] = Y->p[i] * ( 1 - swap ) + tmp * swap;
}
cleanup:
return( ret );
}
/*
* Set value from integer
*/
int mbedtls_mpi_lset( mbedtls_mpi *X, mbedtls_mpi_sint z )
{
int ret;
MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, 1 ) );
memset( X->p, 0, X->n * ciL );
X->p[0] = ( z < 0 ) ? -z : z;
X->s = ( z < 0 ) ? -1 : 1;
cleanup:
return( ret );
}
/*
* Get a specific bit
*/
int mbedtls_mpi_get_bit( const mbedtls_mpi *X, size_t pos )
{
if( X->n * biL <= pos )
return( 0 );
return( ( X->p[pos / biL] >> ( pos % biL ) ) & 0x01 );
}
/*
* Set a bit to a specific value of 0 or 1
*/
int mbedtls_mpi_set_bit( mbedtls_mpi *X, size_t pos, unsigned char val )
{
int ret = 0;
size_t off = pos / biL;
size_t idx = pos % biL;
if( val != 0 && val != 1 )
return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
if( X->n * biL <= pos )
{
if( val == 0 )
return( 0 );
MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, off + 1 ) );
}
X->p[off] &= ~( (mbedtls_mpi_uint) 0x01 << idx );
X->p[off] |= (mbedtls_mpi_uint) val << idx;
cleanup:
return( ret );
}
/*
* Return the number of less significant zero-bits
*/
size_t mbedtls_mpi_lsb( const mbedtls_mpi *X )
{
size_t i, j, count = 0;
for( i = 0; i < X->n; i++ )
for( j = 0; j < biL; j++, count++ )
if( ( ( X->p[i] >> j ) & 1 ) != 0 )
return( count );
return( 0 );
}
/*
* Count leading zero bits in a given integer
*/
static size_t mbedtls_clz( const mbedtls_mpi_uint x )
{
size_t j;
mbedtls_mpi_uint mask = (mbedtls_mpi_uint) 1 << (biL - 1);
for( j = 0; j < biL; j++ )
{
if( x & mask ) break;
mask >>= 1;
}
return j;
}
/*
* Return the number of bits
*/
size_t mbedtls_mpi_bitlen( const mbedtls_mpi *X )
{
size_t i, j;
if( X->n == 0 )
return( 0 );
for( i = X->n - 1; i > 0; i-- )
if( X->p[i] != 0 )
break;
j = biL - mbedtls_clz( X->p[i] );
return( ( i * biL ) + j );
}
/*
* Return the total size in bytes
*/
size_t mbedtls_mpi_size( const mbedtls_mpi *X )
{
return( ( mbedtls_mpi_bitlen( X ) + 7 ) >> 3 );
}
/*
* Convert an ASCII character to digit value
*/
static int mpi_get_digit( mbedtls_mpi_uint *d, int radix, char c )
{
*d = 255;
if( c >= 0x30 && c <= 0x39 ) *d = c - 0x30;
if( c >= 0x41 && c <= 0x46 ) *d = c - 0x37;
if( c >= 0x61 && c <= 0x66 ) *d = c - 0x57;
if( *d >= (mbedtls_mpi_uint) radix )
return( MBEDTLS_ERR_MPI_INVALID_CHARACTER );
return( 0 );
}
/*
* Import from an ASCII string
*/
int mbedtls_mpi_read_string( mbedtls_mpi *X, int radix, const char *s )
{
int ret;
size_t i, j, slen, n;
mbedtls_mpi_uint d;
mbedtls_mpi T;
if( radix < 2 || radix > 16 )
return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
mbedtls_mpi_init( &T );
slen = strlen( s );
if( radix == 16 )
{
if( slen > MPI_SIZE_T_MAX >> 2 )
return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
n = BITS_TO_LIMBS( slen << 2 );
MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, n ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
for( i = slen, j = 0; i > 0; i--, j++ )
{
if( i == 1 && s[i - 1] == '-' )
{
X->s = -1;
break;
}
MBEDTLS_MPI_CHK( mpi_get_digit( &d, radix, s[i - 1] ) );
X->p[j / ( 2 * ciL )] |= d << ( ( j % ( 2 * ciL ) ) << 2 );
}
}
else
{
MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
for( i = 0; i < slen; i++ )
{
if( i == 0 && s[i] == '-' )
{
X->s = -1;
continue;
}
MBEDTLS_MPI_CHK( mpi_get_digit( &d, radix, s[i] ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T, X, radix ) );
if( X->s == 1 )
{
MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, &T, d ) );
}
else
{
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( X, &T, d ) );
}
}
}
cleanup:
mbedtls_mpi_free( &T );
return( ret );
}
/*
* Helper to write the digits high-order first
*/
static int mpi_write_hlp( mbedtls_mpi *X, int radix, char **p )
{
int ret;
mbedtls_mpi_uint r;
if( radix < 2 || radix > 16 )
return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, radix ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_div_int( X, NULL, X, radix ) );
if( mbedtls_mpi_cmp_int( X, 0 ) != 0 )
MBEDTLS_MPI_CHK( mpi_write_hlp( X, radix, p ) );
if( r < 10 )
*(*p)++ = (char)( r + 0x30 );
else
*(*p)++ = (char)( r + 0x37 );
cleanup:
return( ret );
}
/*
* Export into an ASCII string
*/
int mbedtls_mpi_write_string( const mbedtls_mpi *X, int radix,
char *buf, size_t buflen, size_t *olen )
{
int ret = 0;
size_t n;
char *p;
mbedtls_mpi T;
if( radix < 2 || radix > 16 )
return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
n = mbedtls_mpi_bitlen( X );
if( radix >= 4 ) n >>= 1;
if( radix >= 16 ) n >>= 1;
n += 3;
if( buflen < n )
{
*olen = n;
return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
}
p = buf;
mbedtls_mpi_init( &T );
if( X->s == -1 )
*p++ = '-';
if( radix == 16 )
{
int c;
size_t i, j, k;
for( i = X->n, k = 0; i > 0; i-- )
{
for( j = ciL; j > 0; j-- )
{
c = ( X->p[i - 1] >> ( ( j - 1 ) << 3) ) & 0xFF;
if( c == 0 && k == 0 && ( i + j ) != 2 )
continue;
*(p++) = "0123456789ABCDEF" [c / 16];
*(p++) = "0123456789ABCDEF" [c % 16];
k = 1;
}
}
}
else
{
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &T, X ) );
if( T.s == -1 )
T.s = 1;
MBEDTLS_MPI_CHK( mpi_write_hlp( &T, radix, &p ) );
}
*p++ = '\0';
*olen = p - buf;
cleanup:
mbedtls_mpi_free( &T );
return( ret );
}
#if defined(MBEDTLS_FS_IO)
/*
* Read X from an opened file
*/
int mbedtls_mpi_read_file( mbedtls_mpi *X, int radix, FILE *fin )
{
mbedtls_mpi_uint d;
size_t slen;
char *p;
/*
* Buffer should have space for (short) label and decimal formatted MPI,
* newline characters and '\0'
*/
char s[ MBEDTLS_MPI_RW_BUFFER_SIZE ];
memset( s, 0, sizeof( s ) );
if( fgets( s, sizeof( s ) - 1, fin ) == NULL )
return( MBEDTLS_ERR_MPI_FILE_IO_ERROR );
slen = strlen( s );
if( slen == sizeof( s ) - 2 )
return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
if( s[slen - 1] == '\n' ) { slen--; s[slen] = '\0'; }
if( s[slen - 1] == '\r' ) { slen--; s[slen] = '\0'; }
p = s + slen;
while( --p >= s )
if( mpi_get_digit( &d, radix, *p ) != 0 )
break;
return( mbedtls_mpi_read_string( X, radix, p + 1 ) );
}
/*
* Write X into an opened file (or stdout if fout == NULL)
*/
int mbedtls_mpi_write_file( const char *p, const mbedtls_mpi *X, int radix, FILE *fout )
{
int ret;
size_t n, slen, plen;
/*
* Buffer should have space for (short) label and decimal formatted MPI,
* newline characters and '\0'
*/
char s[ MBEDTLS_MPI_RW_BUFFER_SIZE ];
memset( s, 0, sizeof( s ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_write_string( X, radix, s, sizeof( s ) - 2, &n ) );
if( p == NULL ) p = "";
plen = strlen( p );
slen = strlen( s );
s[slen++] = '\r';
s[slen++] = '\n';
if( fout != NULL )
{
if( fwrite( p, 1, plen, fout ) != plen ||
fwrite( s, 1, slen, fout ) != slen )
return( MBEDTLS_ERR_MPI_FILE_IO_ERROR );
}
else
mbedtls_printf( "%s%s", p, s );
cleanup:
return( ret );
}
#endif /* MBEDTLS_FS_IO */
/*
* Import X from unsigned binary data, big endian
*/
int mbedtls_mpi_read_binary( mbedtls_mpi *X, const unsigned char *buf, size_t buflen )
{
int ret;
size_t i, j, n;
for( n = 0; n < buflen; n++ )
if( buf[n] != 0 )
break;
MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, CHARS_TO_LIMBS( buflen - n ) ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
for( i = buflen, j = 0; i > n; i--, j++ )
X->p[j / ciL] |= ((mbedtls_mpi_uint) buf[i - 1]) << ((j % ciL) << 3);
cleanup:
return( ret );
}
/*
* Export X into unsigned binary data, big endian
*/
int mbedtls_mpi_write_binary( const mbedtls_mpi *X, unsigned char *buf, size_t buflen )
{
size_t i, j, n;
n = mbedtls_mpi_size( X );
if( buflen < n )
return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
memset( buf, 0, buflen );
for( i = buflen - 1, j = 0; n > 0; i--, j++, n-- )
buf[i] = (unsigned char)( X->p[j / ciL] >> ((j % ciL) << 3) );
return( 0 );
}
/*
* Left-shift: X <<= count
*/
int mbedtls_mpi_shift_l( mbedtls_mpi *X, size_t count )
{
int ret;
size_t i, v0, t1;
mbedtls_mpi_uint r0 = 0, r1;
v0 = count / (biL );
t1 = count & (biL - 1);
i = mbedtls_mpi_bitlen( X ) + count;
if( X->n * biL < i )
MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, BITS_TO_LIMBS( i ) ) );
ret = 0;
/*
* shift by count / limb_size
*/
if( v0 > 0 )
{
for( i = X->n; i > v0; i-- )
X->p[i - 1] = X->p[i - v0 - 1];
for( ; i > 0; i-- )
X->p[i - 1] = 0;
}
/*
* shift by count % limb_size
*/
if( t1 > 0 )
{
for( i = v0; i < X->n; i++ )
{
r1 = X->p[i] >> (biL - t1);
X->p[i] <<= t1;
X->p[i] |= r0;
r0 = r1;
}
}
cleanup:
return( ret );
}
/*
* Right-shift: X >>= count
*/
int mbedtls_mpi_shift_r( mbedtls_mpi *X, size_t count )
{
size_t i, v0, v1;
mbedtls_mpi_uint r0 = 0, r1;
v0 = count / biL;
v1 = count & (biL - 1);
if( v0 > X->n || ( v0 == X->n && v1 > 0 ) )
return mbedtls_mpi_lset( X, 0 );
/*
* shift by count / limb_size
*/
if( v0 > 0 )
{
for( i = 0; i < X->n - v0; i++ )
X->p[i] = X->p[i + v0];
for( ; i < X->n; i++ )
X->p[i] = 0;
}
/*
* shift by count % limb_size
*/
if( v1 > 0 )
{
for( i = X->n; i > 0; i-- )
{
r1 = X->p[i - 1] << (biL - v1);
X->p[i - 1] >>= v1;
X->p[i - 1] |= r0;
r0 = r1;
}
}
return( 0 );
}
/*
* Compare unsigned values
*/
int mbedtls_mpi_cmp_abs( const mbedtls_mpi *X, const mbedtls_mpi *Y )
{
size_t i, j;
for( i = X->n; i > 0; i-- )
if( X->p[i - 1] != 0 )
break;
for( j = Y->n; j > 0; j-- )
if( Y->p[j - 1] != 0 )
break;
if( i == 0 && j == 0 )
return( 0 );
if( i > j ) return( 1 );
if( j > i ) return( -1 );
for( ; i > 0; i-- )
{
if( X->p[i - 1] > Y->p[i - 1] ) return( 1 );
if( X->p[i - 1] < Y->p[i - 1] ) return( -1 );
}
return( 0 );
}
/*
* Compare signed values
*/
int mbedtls_mpi_cmp_mpi( const mbedtls_mpi *X, const mbedtls_mpi *Y )
{
size_t i, j;
for( i = X->n; i > 0; i-- )
if( X->p[i - 1] != 0 )
break;
for( j = Y->n; j > 0; j-- )
if( Y->p[j - 1] != 0 )
break;
if( i == 0 && j == 0 )
return( 0 );
if( i > j ) return( X->s );
if( j > i ) return( -Y->s );
if( X->s > 0 && Y->s < 0 ) return( 1 );
if( Y->s > 0 && X->s < 0 ) return( -1 );
for( ; i > 0; i-- )
{
if( X->p[i - 1] > Y->p[i - 1] ) return( X->s );
if( X->p[i - 1] < Y->p[i - 1] ) return( -X->s );
}
return( 0 );
}
/*
* Compare signed values
*/
int mbedtls_mpi_cmp_int( const mbedtls_mpi *X, mbedtls_mpi_sint z )
{
mbedtls_mpi Y;
mbedtls_mpi_uint p[1];
*p = ( z < 0 ) ? -z : z;
Y.s = ( z < 0 ) ? -1 : 1;
Y.n = 1;
Y.p = p;
return( mbedtls_mpi_cmp_mpi( X, &Y ) );
}
/*
* Unsigned addition: X = |A| + |B| (HAC 14.7)
*/
int mbedtls_mpi_add_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
{
int ret;
size_t i, j;
mbedtls_mpi_uint *o, *p, c;
if( X == B )
{
const mbedtls_mpi *T = A; A = X; B = T;
}
if( X != A )
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, A ) );
/*
* X should always be positive as a result of unsigned additions.
*/
X->s = 1;
for( j = B->n; j > 0; j-- )
if( B->p[j - 1] != 0 )
break;
MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) );
o = B->p; p = X->p; c = 0;
for( i = 0; i < j; i++, o++, p++ )
{
*p += c; c = ( *p < c );
*p += *o; c += ( *p < *o );
}
while( c != 0 )
{
if( i >= X->n )
{
MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i + 1 ) );
p = X->p + i;
}
*p += c; c = ( *p < c ); i++; p++;
}
cleanup:
return( ret );
}
/*
* Helper for mbedtls_mpi subtraction
*/
static void mpi_sub_hlp( size_t n, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d )
{
size_t i;
mbedtls_mpi_uint c, z;
for( i = c = 0; i < n; i++, s++, d++ )
{
z = ( *d < c ); *d -= c;
c = ( *d < *s ) + z; *d -= *s;
}
while( c != 0 )
{
z = ( *d < c ); *d -= c;
c = z; i++; d++;
}
}
/*
* Unsigned subtraction: X = |A| - |B| (HAC 14.9)
*/
int mbedtls_mpi_sub_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
{
mbedtls_mpi TB;
int ret;
size_t n;
if( mbedtls_mpi_cmp_abs( A, B ) < 0 )
return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE );
mbedtls_mpi_init( &TB );
if( X == B )
{
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) );
B = &TB;
}
if( X != A )
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, A ) );
/*
* X should always be positive as a result of unsigned subtractions.
*/
X->s = 1;
ret = 0;
for( n = B->n; n > 0; n-- )
if( B->p[n - 1] != 0 )
break;
mpi_sub_hlp( n, B->p, X->p );
cleanup:
mbedtls_mpi_free( &TB );
return( ret );
}
/*
* Signed addition: X = A + B
*/
int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
{
int ret, s = A->s;
if( A->s * B->s < 0 )
{
if( mbedtls_mpi_cmp_abs( A, B ) >= 0 )
{
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, A, B ) );
X->s = s;
}
else
{
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, B, A ) );
X->s = -s;
}
}
else
{
MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( X, A, B ) );
X->s = s;
}
cleanup:
return( ret );
}
/*
* Signed subtraction: X = A - B
*/
int mbedtls_mpi_sub_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
{
int ret, s = A->s;
if( A->s * B->s > 0 )
{
if( mbedtls_mpi_cmp_abs( A, B ) >= 0 )
{
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, A, B ) );
X->s = s;
}
else
{
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, B, A ) );
X->s = -s;
}
}
else
{
MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( X, A, B ) );
X->s = s;
}
cleanup:
return( ret );
}
/*
* Signed addition: X = A + b
*/
int mbedtls_mpi_add_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b )
{
mbedtls_mpi _B;
mbedtls_mpi_uint p[1];
p[0] = ( b < 0 ) ? -b : b;
_B.s = ( b < 0 ) ? -1 : 1;
_B.n = 1;
_B.p = p;
return( mbedtls_mpi_add_mpi( X, A, &_B ) );
}
/*
* Signed subtraction: X = A - b
*/
int mbedtls_mpi_sub_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b )
{
mbedtls_mpi _B;
mbedtls_mpi_uint p[1];
p[0] = ( b < 0 ) ? -b : b;
_B.s = ( b < 0 ) ? -1 : 1;
_B.n = 1;
_B.p = p;
return( mbedtls_mpi_sub_mpi( X, A, &_B ) );
}
/*
* Helper for mbedtls_mpi multiplication
*/
static
#if defined(__APPLE__) && defined(__arm__)
/*
* Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn)
* appears to need this to prevent bad ARM code generation at -O3.
*/
__attribute__ ((noinline))
#endif
void mpi_mul_hlp( size_t i, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d, mbedtls_mpi_uint b )
{
mbedtls_mpi_uint c = 0, t = 0;
#if defined(MULADDC_HUIT)
for( ; i >= 8; i -= 8 )
{
MULADDC_INIT
MULADDC_HUIT
MULADDC_STOP
}
for( ; i > 0; i-- )
{
MULADDC_INIT
MULADDC_CORE
MULADDC_STOP
}
#else /* MULADDC_HUIT */
for( ; i >= 16; i -= 16 )
{
MULADDC_INIT
MULADDC_CORE MULADDC_CORE
MULADDC_CORE MULADDC_CORE
MULADDC_CORE MULADDC_CORE
MULADDC_CORE MULADDC_CORE
MULADDC_CORE MULADDC_CORE
MULADDC_CORE MULADDC_CORE
MULADDC_CORE MULADDC_CORE
MULADDC_CORE MULADDC_CORE
MULADDC_STOP
}
for( ; i >= 8; i -= 8 )
{
MULADDC_INIT
MULADDC_CORE MULADDC_CORE
MULADDC_CORE MULADDC_CORE
MULADDC_CORE MULADDC_CORE
MULADDC_CORE MULADDC_CORE
MULADDC_STOP
}
for( ; i > 0; i-- )
{
MULADDC_INIT
MULADDC_CORE
MULADDC_STOP
}
#endif /* MULADDC_HUIT */
t++;
do {
*d += c; c = ( *d < c ); d++;
}
while( c != 0 );
}
/*
* Baseline multiplication: X = A * B (HAC 14.12)
*/
int mbedtls_mpi_mul_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
{
int ret;
size_t i, j;
mbedtls_mpi TA, TB;
mbedtls_mpi_init( &TA ); mbedtls_mpi_init( &TB );
if( X == A ) { MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TA, A ) ); A = &TA; }
if( X == B ) { MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) ); B = &TB; }
for( i = A->n; i > 0; i-- )
if( A->p[i - 1] != 0 )
break;
for( j = B->n; j > 0; j-- )
if( B->p[j - 1] != 0 )
break;
MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i + j ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
for( i++; j > 0; j-- )
mpi_mul_hlp( i - 1, A->p, X->p + j - 1, B->p[j - 1] );
X->s = A->s * B->s;
cleanup:
mbedtls_mpi_free( &TB ); mbedtls_mpi_free( &TA );
return( ret );
}
/*
* Baseline multiplication: X = A * b
*/
int mbedtls_mpi_mul_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint b )
{
mbedtls_mpi _B;
mbedtls_mpi_uint p[1];
_B.s = 1;
_B.n = 1;
_B.p = p;
p[0] = b;
return( mbedtls_mpi_mul_mpi( X, A, &_B ) );
}
/*
* Unsigned integer divide - double mbedtls_mpi_uint dividend, u1/u0, and
* mbedtls_mpi_uint divisor, d
*/
static mbedtls_mpi_uint mbedtls_int_div_int( mbedtls_mpi_uint u1,
mbedtls_mpi_uint u0, mbedtls_mpi_uint d, mbedtls_mpi_uint *r )
{
#if defined(MBEDTLS_HAVE_UDBL)
mbedtls_t_udbl dividend, quotient;
#else
const mbedtls_mpi_uint radix = (mbedtls_mpi_uint) 1 << biH;
const mbedtls_mpi_uint uint_halfword_mask = ( (mbedtls_mpi_uint) 1 << biH ) - 1;
mbedtls_mpi_uint d0, d1, q0, q1, rAX, r0, quotient;
mbedtls_mpi_uint u0_msw, u0_lsw;
size_t s;
#endif
/*
* Check for overflow
*/
if( 0 == d || u1 >= d )
{
if (r != NULL) *r = ~0;
return ( ~0 );
}
#if defined(MBEDTLS_HAVE_UDBL)
dividend = (mbedtls_t_udbl) u1 << biL;
dividend |= (mbedtls_t_udbl) u0;
quotient = dividend / d;
if( quotient > ( (mbedtls_t_udbl) 1 << biL ) - 1 )
quotient = ( (mbedtls_t_udbl) 1 << biL ) - 1;
if( r != NULL )
*r = (mbedtls_mpi_uint)( dividend - (quotient * d ) );
return (mbedtls_mpi_uint) quotient;
#else
/*
* Algorithm D, Section 4.3.1 - The Art of Computer Programming
* Vol. 2 - Seminumerical Algorithms, Knuth
*/
/*
* Normalize the divisor, d, and dividend, u0, u1
*/
s = mbedtls_clz( d );
d = d << s;
u1 = u1 << s;
u1 |= ( u0 >> ( biL - s ) ) & ( -(mbedtls_mpi_sint)s >> ( biL - 1 ) );
u0 = u0 << s;
d1 = d >> biH;
d0 = d & uint_halfword_mask;
u0_msw = u0 >> biH;
u0_lsw = u0 & uint_halfword_mask;
/*
* Find the first quotient and remainder
*/
q1 = u1 / d1;
r0 = u1 - d1 * q1;
while( q1 >= radix || ( q1 * d0 > radix * r0 + u0_msw ) )
{
q1 -= 1;
r0 += d1;
if ( r0 >= radix ) break;
}
rAX = ( u1 * radix ) + ( u0_msw - q1 * d );
q0 = rAX / d1;
r0 = rAX - q0 * d1;
while( q0 >= radix || ( q0 * d0 > radix * r0 + u0_lsw ) )
{
q0 -= 1;
r0 += d1;
if ( r0 >= radix ) break;
}
if (r != NULL)
*r = ( rAX * radix + u0_lsw - q0 * d ) >> s;
quotient = q1 * radix + q0;
return quotient;
#endif
}
/*
* Division by mbedtls_mpi: A = Q * B + R (HAC 14.20)
*/
int mbedtls_mpi_div_mpi( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B )
{
int ret;
size_t i, n, t, k;
mbedtls_mpi X, Y, Z, T1, T2;
if( mbedtls_mpi_cmp_int( B, 0 ) == 0 )
return( MBEDTLS_ERR_MPI_DIVISION_BY_ZERO );
mbedtls_mpi_init( &X ); mbedtls_mpi_init( &Y ); mbedtls_mpi_init( &Z );
mbedtls_mpi_init( &T1 ); mbedtls_mpi_init( &T2 );
if( mbedtls_mpi_cmp_abs( A, B ) < 0 )
{
if( Q != NULL ) MBEDTLS_MPI_CHK( mbedtls_mpi_lset( Q, 0 ) );
if( R != NULL ) MBEDTLS_MPI_CHK( mbedtls_mpi_copy( R, A ) );
return( 0 );
}
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &X, A ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Y, B ) );
X.s = Y.s = 1;
MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &Z, A->n + 2 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &Z, 0 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T1, 2 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T2, 3 ) );
k = mbedtls_mpi_bitlen( &Y ) % biL;
if( k < biL - 1 )
{
k = biL - 1 - k;
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &X, k ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &Y, k ) );
}
else k = 0;
n = X.n - 1;
t = Y.n - 1;
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &Y, biL * ( n - t ) ) );
while( mbedtls_mpi_cmp_mpi( &X, &Y ) >= 0 )
{
Z.p[n - t]++;
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &Y ) );
}
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &Y, biL * ( n - t ) ) );
for( i = n; i > t ; i-- )
{
if( X.p[i] >= Y.p[t] )
Z.p[i - t - 1] = ~0;
else
{
Z.p[i - t - 1] = mbedtls_int_div_int( X.p[i], X.p[i - 1],
Y.p[t], NULL);
}
Z.p[i - t - 1]++;
do
{
Z.p[i - t - 1]--;
MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &T1, 0 ) );
T1.p[0] = ( t < 1 ) ? 0 : Y.p[t - 1];
T1.p[1] = Y.p[t];
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T1, &T1, Z.p[i - t - 1] ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &T2, 0 ) );
T2.p[0] = ( i < 2 ) ? 0 : X.p[i - 2];
T2.p[1] = ( i < 1 ) ? 0 : X.p[i - 1];
T2.p[2] = X.p[i];
}
while( mbedtls_mpi_cmp_mpi( &T1, &T2 ) > 0 );
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T1, &Y, Z.p[i - t - 1] ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &T1, biL * ( i - t - 1 ) ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &T1 ) );
if( mbedtls_mpi_cmp_int( &X, 0 ) < 0 )
{
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &T1, &Y ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &T1, biL * ( i - t - 1 ) ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &X, &X, &T1 ) );
Z.p[i - t - 1]--;
}
}
if( Q != NULL )
{
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( Q, &Z ) );
Q->s = A->s * B->s;
}
if( R != NULL )
{
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &X, k ) );
X.s = A->s;
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( R, &X ) );
if( mbedtls_mpi_cmp_int( R, 0 ) == 0 )
R->s = 1;
}
cleanup:
mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &Z );
mbedtls_mpi_free( &T1 ); mbedtls_mpi_free( &T2 );
return( ret );
}
/*
* Division by int: A = Q * b + R
*/
int mbedtls_mpi_div_int( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, mbedtls_mpi_sint b )
{
mbedtls_mpi _B;
mbedtls_mpi_uint p[1];
p[0] = ( b < 0 ) ? -b : b;
_B.s = ( b < 0 ) ? -1 : 1;
_B.n = 1;
_B.p = p;
return( mbedtls_mpi_div_mpi( Q, R, A, &_B ) );
}
/*
* Modulo: R = A mod B
*/
int mbedtls_mpi_mod_mpi( mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B )
{
int ret;
if( mbedtls_mpi_cmp_int( B, 0 ) < 0 )
return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE );
MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( NULL, R, A, B ) );
while( mbedtls_mpi_cmp_int( R, 0 ) < 0 )
MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( R, R, B ) );
while( mbedtls_mpi_cmp_mpi( R, B ) >= 0 )
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( R, R, B ) );
cleanup:
return( ret );
}
/*
* Modulo: r = A mod b
*/
int mbedtls_mpi_mod_int( mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_sint b )
{
size_t i;
mbedtls_mpi_uint x, y, z;
if( b == 0 )
return( MBEDTLS_ERR_MPI_DIVISION_BY_ZERO );
if( b < 0 )
return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE );
/*
* handle trivial cases
*/
if( b == 1 )
{
*r = 0;
return( 0 );
}
if( b == 2 )
{
*r = A->p[0] & 1;
return( 0 );
}
/*
* general case
*/
for( i = A->n, y = 0; i > 0; i-- )
{
x = A->p[i - 1];
y = ( y << biH ) | ( x >> biH );
z = y / b;
y -= z * b;
x <<= biH;
y = ( y << biH ) | ( x >> biH );
z = y / b;
y -= z * b;
}
/*
* If A is negative, then the current y represents a negative value.
* Flipping it to the positive side.
*/
if( A->s < 0 && y != 0 )
y = b - y;
*r = y;
return( 0 );
}
/*
* Fast Montgomery initialization (thanks to Tom St Denis)
*/
static void mpi_montg_init( mbedtls_mpi_uint *mm, const mbedtls_mpi *N )
{
mbedtls_mpi_uint x, m0 = N->p[0];
unsigned int i;
x = m0;
x += ( ( m0 + 2 ) & 4 ) << 1;
for( i = biL; i >= 8; i /= 2 )
x *= ( 2 - ( m0 * x ) );
*mm = ~x + 1;
}
/*
* Montgomery multiplication: A = A * B * R^-1 mod N (HAC 14.36)
*/
static void mpi_montmul( mbedtls_mpi *A, const mbedtls_mpi *B, const mbedtls_mpi *N, mbedtls_mpi_uint mm,
const mbedtls_mpi *T )
{
size_t i, n, m;
mbedtls_mpi_uint u0, u1, *d;
memset( T->p, 0, T->n * ciL );
d = T->p;
n = N->n;
m = ( B->n < n ) ? B->n : n;
for( i = 0; i < n; i++ )
{
/*
* T = (T + u0*B + u1*N) / 2^biL
*/
u0 = A->p[i];
u1 = ( d[0] + u0 * B->p[0] ) * mm;
mpi_mul_hlp( m, B->p, d, u0 );
mpi_mul_hlp( n, N->p, d, u1 );
*d++ = u0; d[n + 1] = 0;
}
memcpy( A->p, d, ( n + 1 ) * ciL );
if( mbedtls_mpi_cmp_abs( A, N ) >= 0 )
mpi_sub_hlp( n, N->p, A->p );
else
/* prevent timing attacks */
mpi_sub_hlp( n, A->p, T->p );
}
/*
* Montgomery reduction: A = A * R^-1 mod N
*/
static void mpi_montred( mbedtls_mpi *A, const mbedtls_mpi *N, mbedtls_mpi_uint mm, const mbedtls_mpi *T )
{
mbedtls_mpi_uint z = 1;
mbedtls_mpi U;
U.n = U.s = (int) z;
U.p = &z;
mpi_montmul( A, &U, N, mm, T );
}
/*
* Sliding-window exponentiation: X = A^E mod N (HAC 14.85)
*/
int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *E, const mbedtls_mpi *N, mbedtls_mpi *_RR )
{
int ret;
size_t wbits, wsize, one = 1;
size_t i, j, nblimbs;
size_t bufsize, nbits;
mbedtls_mpi_uint ei, mm, state;
mbedtls_mpi RR, T, W[ 2 << MBEDTLS_MPI_WINDOW_SIZE ], Apos;
int neg;
if( mbedtls_mpi_cmp_int( N, 0 ) < 0 || ( N->p[0] & 1 ) == 0 )
return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
if( mbedtls_mpi_cmp_int( E, 0 ) < 0 )
return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
/*
* Init temps and window size
*/
mpi_montg_init( &mm, N );
mbedtls_mpi_init( &RR ); mbedtls_mpi_init( &T );
mbedtls_mpi_init( &Apos );
memset( W, 0, sizeof( W ) );
i = mbedtls_mpi_bitlen( E );
wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 :
( i > 79 ) ? 4 : ( i > 23 ) ? 3 : 1;
if( wsize > MBEDTLS_MPI_WINDOW_SIZE )
wsize = MBEDTLS_MPI_WINDOW_SIZE;
j = N->n + 1;
MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[1], j ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T, j * 2 ) );
/*
* Compensate for negative A (and correct at the end)
*/
neg = ( A->s == -1 );
if( neg )
{
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Apos, A ) );
Apos.s = 1;
A = &Apos;
}
/*
* If 1st call, pre-compute R^2 mod N
*/
if( _RR == NULL || _RR->p == NULL )
{
MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &RR, 1 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &RR, N->n * 2 * biL ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &RR, &RR, N ) );
if( _RR != NULL )
memcpy( _RR, &RR, sizeof( mbedtls_mpi ) );
}
else
memcpy( &RR, _RR, sizeof( mbedtls_mpi ) );
/*
* W[1] = A * R^2 * R^-1 mod N = A * R mod N
*/
if( mbedtls_mpi_cmp_mpi( A, N ) >= 0 )
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &W[1], A, N ) );
else
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[1], A ) );
mpi_montmul( &W[1], &RR, N, mm, &T );
/*
* X = R^2 * R^-1 mod N = R mod N
*/
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, &RR ) );
mpi_montred( X, N, mm, &T );
if( wsize > 1 )
{
/*
* W[1 << (wsize - 1)] = W[1] ^ (wsize - 1)
*/
j = one << ( wsize - 1 );
MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[j], N->n + 1 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[j], &W[1] ) );
for( i = 0; i < wsize - 1; i++ )
mpi_montmul( &W[j], &W[j], N, mm, &T );
/*
* W[i] = W[i - 1] * W[1]
*/
for( i = j + 1; i < ( one << wsize ); i++ )
{
MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[i], N->n + 1 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[i], &W[i - 1] ) );
mpi_montmul( &W[i], &W[1], N, mm, &T );
}
}
nblimbs = E->n;
bufsize = 0;
nbits = 0;
wbits = 0;
state = 0;
while( 1 )
{
if( bufsize == 0 )
{
if( nblimbs == 0 )
break;
nblimbs--;
bufsize = sizeof( mbedtls_mpi_uint ) << 3;
}
bufsize--;
ei = (E->p[nblimbs] >> bufsize) & 1;
/*
* skip leading 0s
*/
if( ei == 0 && state == 0 )
continue;
if( ei == 0 && state == 1 )
{
/*
* out of window, square X
*/
mpi_montmul( X, X, N, mm, &T );
continue;
}
/*
* add ei to current window
*/
state = 2;
nbits++;
wbits |= ( ei << ( wsize - nbits ) );
if( nbits == wsize )
{
/*
* X = X^wsize R^-1 mod N
*/
for( i = 0; i < wsize; i++ )
mpi_montmul( X, X, N, mm, &T );
/*
* X = X * W[wbits] R^-1 mod N
*/
mpi_montmul( X, &W[wbits], N, mm, &T );
state--;
nbits = 0;
wbits = 0;
}
}
/*
* process the remaining bits
*/
for( i = 0; i < nbits; i++ )
{
mpi_montmul( X, X, N, mm, &T );
wbits <<= 1;
if( ( wbits & ( one << wsize ) ) != 0 )
mpi_montmul( X, &W[1], N, mm, &T );
}
/*
* X = A^E * R * R^-1 mod N = A^E mod N
*/
mpi_montred( X, N, mm, &T );
if( neg )
{
X->s = -1;
MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( X, N, X ) );
}
cleanup:
for( i = ( one << ( wsize - 1 ) ); i < ( one << wsize ); i++ )
mbedtls_mpi_free( &W[i] );
mbedtls_mpi_free( &W[1] ); mbedtls_mpi_free( &T ); mbedtls_mpi_free( &Apos );
if( _RR == NULL || _RR->p == NULL )
mbedtls_mpi_free( &RR );
return( ret );
}
/*
* Greatest common divisor: G = gcd(A, B) (HAC 14.54)
*/
int mbedtls_mpi_gcd( mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B )
{
int ret;
size_t lz, lzt;
mbedtls_mpi TG, TA, TB;
mbedtls_mpi_init( &TG ); mbedtls_mpi_init( &TA ); mbedtls_mpi_init( &TB );
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TA, A ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) );
lz = mbedtls_mpi_lsb( &TA );
lzt = mbedtls_mpi_lsb( &TB );
if( lzt < lz )
lz = lzt;
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, lz ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, lz ) );
TA.s = TB.s = 1;
while( mbedtls_mpi_cmp_int( &TA, 0 ) != 0 )
{
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, mbedtls_mpi_lsb( &TA ) ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, mbedtls_mpi_lsb( &TB ) ) );
if( mbedtls_mpi_cmp_mpi( &TA, &TB ) >= 0 )
{
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &TA, &TA, &TB ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, 1 ) );
}
else
{
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &TB, &TB, &TA ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, 1 ) );
}
}
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &TB, lz ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( G, &TB ) );
cleanup:
mbedtls_mpi_free( &TG ); mbedtls_mpi_free( &TA ); mbedtls_mpi_free( &TB );
return( ret );
}
/*
* Fill X with size bytes of random.
*
* Use a temporary bytes representation to make sure the result is the same
* regardless of the platform endianness (useful when f_rng is actually
* deterministic, eg for tests).
*/
int mbedtls_mpi_fill_random( mbedtls_mpi *X, size_t size,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng )
{
int ret;
unsigned char buf[MBEDTLS_MPI_MAX_SIZE];
if( size > MBEDTLS_MPI_MAX_SIZE )
return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
MBEDTLS_MPI_CHK( f_rng( p_rng, buf, size ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( X, buf, size ) );
cleanup:
return( ret );
}
/*
* Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64)
*/
int mbedtls_mpi_inv_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N )
{
int ret;
mbedtls_mpi G, TA, TU, U1, U2, TB, TV, V1, V2;
if( mbedtls_mpi_cmp_int( N, 0 ) <= 0 )
return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
mbedtls_mpi_init( &TA ); mbedtls_mpi_init( &TU ); mbedtls_mpi_init( &U1 ); mbedtls_mpi_init( &U2 );
mbedtls_mpi_init( &G ); mbedtls_mpi_init( &TB ); mbedtls_mpi_init( &TV );
mbedtls_mpi_init( &V1 ); mbedtls_mpi_init( &V2 );
MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G, A, N ) );
if( mbedtls_mpi_cmp_int( &G, 1 ) != 0 )
{
ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
goto cleanup;
}
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &TA, A, N ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TU, &TA ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, N ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TV, N ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &U1, 1 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &U2, 0 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &V1, 0 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &V2, 1 ) );
do
{
while( ( TU.p[0] & 1 ) == 0 )
{
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TU, 1 ) );
if( ( U1.p[0] & 1 ) != 0 || ( U2.p[0] & 1 ) != 0 )
{
MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &U1, &U1, &TB ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U2, &U2, &TA ) );
}
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &U1, 1 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &U2, 1 ) );
}
while( ( TV.p[0] & 1 ) == 0 )
{
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TV, 1 ) );
if( ( V1.p[0] & 1 ) != 0 || ( V2.p[0] & 1 ) != 0 )
{
MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &V1, &V1, &TB ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V2, &V2, &TA ) );
}
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &V1, 1 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &V2, 1 ) );
}
if( mbedtls_mpi_cmp_mpi( &TU, &TV ) >= 0 )
{
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &TU, &TU, &TV ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U1, &U1, &V1 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U2, &U2, &V2 ) );
}
else
{
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &TV, &TV, &TU ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V1, &V1, &U1 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V2, &V2, &U2 ) );
}
}
while( mbedtls_mpi_cmp_int( &TU, 0 ) != 0 );
while( mbedtls_mpi_cmp_int( &V1, 0 ) < 0 )
MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &V1, &V1, N ) );
while( mbedtls_mpi_cmp_mpi( &V1, N ) >= 0 )
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V1, &V1, N ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, &V1 ) );
cleanup:
mbedtls_mpi_free( &TA ); mbedtls_mpi_free( &TU ); mbedtls_mpi_free( &U1 ); mbedtls_mpi_free( &U2 );
mbedtls_mpi_free( &G ); mbedtls_mpi_free( &TB ); mbedtls_mpi_free( &TV );
mbedtls_mpi_free( &V1 ); mbedtls_mpi_free( &V2 );
return( ret );
}
#if defined(MBEDTLS_GENPRIME)
static const int small_prime[] ICACHE_RODATA_ATTR STORE_ATTR =
{
3, 5, 7, 11, 13, 17, 19, 23,
29, 31, 37, 41, 43, 47, 53, 59,
61, 67, 71, 73, 79, 83, 89, 97,
101, 103, 107, 109, 113, 127, 131, 137,
139, 149, 151, 157, 163, 167, 173, 179,
181, 191, 193, 197, 199, 211, 223, 227,
229, 233, 239, 241, 251, 257, 263, 269,
271, 277, 281, 283, 293, 307, 311, 313,
317, 331, 337, 347, 349, 353, 359, 367,
373, 379, 383, 389, 397, 401, 409, 419,
421, 431, 433, 439, 443, 449, 457, 461,
463, 467, 479, 487, 491, 499, 503, 509,
521, 523, 541, 547, 557, 563, 569, 571,
577, 587, 593, 599, 601, 607, 613, 617,
619, 631, 641, 643, 647, 653, 659, 661,
673, 677, 683, 691, 701, 709, 719, 727,
733, 739, 743, 751, 757, 761, 769, 773,
787, 797, 809, 811, 821, 823, 827, 829,
839, 853, 857, 859, 863, 877, 881, 883,
887, 907, 911, 919, 929, 937, 941, 947,
953, 967, 971, 977, 983, 991, 997, -103
};
/*
* Small divisors test (X must be positive)
*
* Return values:
* 0: no small factor (possible prime, more tests needed)
* 1: certain prime
* MBEDTLS_ERR_MPI_NOT_ACCEPTABLE: certain non-prime
* other negative: error
*/
static int mpi_check_small_factors( const mbedtls_mpi *X )
{
int ret = 0;
size_t i;
mbedtls_mpi_uint r;
if( ( X->p[0] & 1 ) == 0 )
return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
for( i = 0; small_prime[i] > 0; i++ )
{
if( mbedtls_mpi_cmp_int( X, small_prime[i] ) <= 0 )
return( 1 );
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, small_prime[i] ) );
if( r == 0 )
return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
}
cleanup:
return( ret );
}
/*
* Miller-Rabin pseudo-primality test (HAC 4.24)
*/
static int mpi_miller_rabin( const mbedtls_mpi *X,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng )
{
int ret, count;
size_t i, j, k, n, s;
mbedtls_mpi W, R, T, A, RR;
mbedtls_mpi_init( &W ); mbedtls_mpi_init( &R ); mbedtls_mpi_init( &T ); mbedtls_mpi_init( &A );
mbedtls_mpi_init( &RR );
/*
* W = |X| - 1
* R = W >> lsb( W )
*/
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &W, X, 1 ) );
s = mbedtls_mpi_lsb( &W );
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R, &W ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &R, s ) );
i = mbedtls_mpi_bitlen( X );
/*
* HAC, table 4.4
*/
n = ( ( i >= 1300 ) ? 2 : ( i >= 850 ) ? 3 :
( i >= 650 ) ? 4 : ( i >= 350 ) ? 8 :
( i >= 250 ) ? 12 : ( i >= 150 ) ? 18 : 27 );
for( i = 0; i < n; i++ )
{
/*
* pick a random A, 1 < A < |X| - 1
*/
MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) );
if( mbedtls_mpi_cmp_mpi( &A, &W ) >= 0 )
{
j = mbedtls_mpi_bitlen( &A ) - mbedtls_mpi_bitlen( &W );
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &A, j + 1 ) );
}
A.p[0] |= 3;
count = 0;
do {
MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) );
j = mbedtls_mpi_bitlen( &A );
k = mbedtls_mpi_bitlen( &W );
if (j > k) {
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &A, j - k ) );
}
if (count++ > 30) {
return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
}
} while ( mbedtls_mpi_cmp_mpi( &A, &W ) >= 0 ||
mbedtls_mpi_cmp_int( &A, 1 ) <= 0 );
/*
* A = A^R mod |X|
*/
MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &A, &A, &R, X, &RR ) );
if( mbedtls_mpi_cmp_mpi( &A, &W ) == 0 ||
mbedtls_mpi_cmp_int( &A, 1 ) == 0 )
continue;
j = 1;
while( j < s && mbedtls_mpi_cmp_mpi( &A, &W ) != 0 )
{
/*
* A = A * A mod |X|
*/
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &A, &A ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &A, &T, X ) );
if( mbedtls_mpi_cmp_int( &A, 1 ) == 0 )
break;
j++;
}
/*
* not prime if A != |X| - 1 or A == 1
*/
if( mbedtls_mpi_cmp_mpi( &A, &W ) != 0 ||
mbedtls_mpi_cmp_int( &A, 1 ) == 0 )
{
ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
break;
}
}
cleanup:
mbedtls_mpi_free( &W ); mbedtls_mpi_free( &R ); mbedtls_mpi_free( &T ); mbedtls_mpi_free( &A );
mbedtls_mpi_free( &RR );
return( ret );
}
/*
* Pseudo-primality test: small factors, then Miller-Rabin
*/
int mbedtls_mpi_is_prime( const mbedtls_mpi *X,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng )
{
int ret;
mbedtls_mpi XX;
XX.s = 1;
XX.n = X->n;
XX.p = X->p;
if( mbedtls_mpi_cmp_int( &XX, 0 ) == 0 ||
mbedtls_mpi_cmp_int( &XX, 1 ) == 0 )
return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
if( mbedtls_mpi_cmp_int( &XX, 2 ) == 0 )
return( 0 );
if( ( ret = mpi_check_small_factors( &XX ) ) != 0 )
{
if( ret == 1 )
return( 0 );
return( ret );
}
return( mpi_miller_rabin( &XX, f_rng, p_rng ) );
}
/*
* Prime number generation
*/
int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int dh_flag,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng )
{
int ret;
size_t k, n;
mbedtls_mpi_uint r;
mbedtls_mpi Y;
if( nbits < 3 || nbits > MBEDTLS_MPI_MAX_BITS )
return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
mbedtls_mpi_init( &Y );
n = BITS_TO_LIMBS( nbits );
MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( X, n * ciL, f_rng, p_rng ) );
k = mbedtls_mpi_bitlen( X );
if( k > nbits ) MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( X, k - nbits + 1 ) );
mbedtls_mpi_set_bit( X, nbits-1, 1 );
X->p[0] |= 1;
if( dh_flag == 0 )
{
while( ( ret = mbedtls_mpi_is_prime( X, f_rng, p_rng ) ) != 0 )
{
if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE )
goto cleanup;
MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 2 ) );
}
}
else
{
/*
* An necessary condition for Y and X = 2Y + 1 to be prime
* is X = 2 mod 3 (which is equivalent to Y = 2 mod 3).
* Make sure it is satisfied, while keeping X = 3 mod 4
*/
X->p[0] |= 2;
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, 3 ) );
if( r == 0 )
MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 8 ) );
else if( r == 1 )
MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 4 ) );
/* Set Y = (X-1) / 2, which is X / 2 because X is odd */
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Y, X ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &Y, 1 ) );
while( 1 )
{
/*
* First, check small factors for X and Y
* before doing Miller-Rabin on any of them
*/
if( ( ret = mpi_check_small_factors( X ) ) == 0 &&
( ret = mpi_check_small_factors( &Y ) ) == 0 &&
( ret = mpi_miller_rabin( X, f_rng, p_rng ) ) == 0 &&
( ret = mpi_miller_rabin( &Y, f_rng, p_rng ) ) == 0 )
{
break;
}
if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE )
goto cleanup;
/*
* Next candidates. We want to preserve Y = (X-1) / 2 and
* Y = 1 mod 2 and Y = 2 mod 3 (eq X = 3 mod 4 and X = 2 mod 3)
* so up Y by 6 and X by 12.
*/
MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 12 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( &Y, &Y, 6 ) );
}
}
cleanup:
mbedtls_mpi_free( &Y );
return( ret );
}
#endif /* MBEDTLS_GENPRIME */
#if defined(MBEDTLS_SELF_TEST)
#define GCD_PAIR_COUNT 3
static const int gcd_pairs[GCD_PAIR_COUNT][3] =
{
{ 693, 609, 21 },
{ 1764, 868, 28 },
{ 768454923, 542167814, 1 }
};
/*
* Checkup routine
*/
int mbedtls_mpi_self_test( int verbose )
{
int ret, i;
mbedtls_mpi A, E, N, X, Y, U, V;
mbedtls_mpi_init( &A ); mbedtls_mpi_init( &E ); mbedtls_mpi_init( &N ); mbedtls_mpi_init( &X );
mbedtls_mpi_init( &Y ); mbedtls_mpi_init( &U ); mbedtls_mpi_init( &V );
MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &A, 16,
"EFE021C2645FD1DC586E69184AF4A31E" \
"D5F53E93B5F123FA41680867BA110131" \
"944FE7952E2517337780CB0DB80E61AA" \
"E7C8DDC6C5C6AADEB34EB38A2F40D5E6" ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &E, 16,
"B2E7EFD37075B9F03FF989C7C5051C20" \
"34D2A323810251127E7BF8625A4F49A5" \
"F3E27F4DA8BD59C47D6DAABA4C8127BD" \
"5B5C25763222FEFCCFC38B832366C29E" ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &N, 16,
"0066A198186C18C10B2F5ED9B522752A" \
"9830B69916E535C8F047518A889A43A5" \
"94B6BED27A168D31D4A52F88925AA8F5" ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &X, &A, &N ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16,
"602AB7ECA597A3D6B56FF9829A5E8B85" \
"9E857EA95A03512E2BAE7391688D264A" \
"A5663B0341DB9CCFD2C4C5F421FEC814" \
"8001B72E848A38CAE1C65F78E56ABDEF" \
"E12D3C039B8A02D6BE593F0BBBDA56F1" \
"ECF677152EF804370C1A305CAF3B5BF1" \
"30879B56C61DE584A0F53A2447A51E" ) );
if( verbose != 0 )
mbedtls_printf( " MPI test #1 (mul_mpi): " );
if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
ret = 1;
goto cleanup;
}
if( verbose != 0 )
mbedtls_printf( "passed\n" );
MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( &X, &Y, &A, &N ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16,
"256567336059E52CAE22925474705F39A94" ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &V, 16,
"6613F26162223DF488E9CD48CC132C7A" \
"0AC93C701B001B092E4E5B9F73BCD27B" \
"9EE50D0657C77F374E903CDFA4C642" ) );
if( verbose != 0 )
mbedtls_printf( " MPI test #2 (div_mpi): " );
if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 ||
mbedtls_mpi_cmp_mpi( &Y, &V ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
ret = 1;
goto cleanup;
}
if( verbose != 0 )
mbedtls_printf( "passed\n" );
MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &X, &A, &E, &N, NULL ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16,
"36E139AEA55215609D2816998ED020BB" \
"BD96C37890F65171D948E9BC7CBAA4D9" \
"325D24D6A3C12710F10A09FA08AB87" ) );
if( verbose != 0 )
mbedtls_printf( " MPI test #3 (exp_mod): " );
if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
ret = 1;
goto cleanup;
}
if( verbose != 0 )
mbedtls_printf( "passed\n" );
MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &X, &A, &N ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16,
"003A0AAEDD7E784FC07D8F9EC6E3BFD5" \
"C3DBA76456363A10869622EAC2DD84EC" \
"C5B8A74DAC4D09E03B5E0BE779F2DF61" ) );
if( verbose != 0 )
mbedtls_printf( " MPI test #4 (inv_mod): " );
if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
ret = 1;
goto cleanup;
}
if( verbose != 0 )
mbedtls_printf( "passed\n" );
if( verbose != 0 )
mbedtls_printf( " MPI test #5 (simple gcd): " );
for( i = 0; i < GCD_PAIR_COUNT; i++ )
{
MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &X, gcd_pairs[i][0] ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &Y, gcd_pairs[i][1] ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &A, &X, &Y ) );
if( mbedtls_mpi_cmp_int( &A, gcd_pairs[i][2] ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed at %d\n", i );
ret = 1;
goto cleanup;
}
}
if( verbose != 0 )
mbedtls_printf( "passed\n" );
cleanup:
if( ret != 0 && verbose != 0 )
mbedtls_printf( "Unexpected error, return code = %08X\n", ret );
mbedtls_mpi_free( &A ); mbedtls_mpi_free( &E ); mbedtls_mpi_free( &N ); mbedtls_mpi_free( &X );
mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &U ); mbedtls_mpi_free( &V );
if( verbose != 0 )
mbedtls_printf( "\n" );
return( ret );
}
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_BIGNUM_C */
/*
* Blowfish implementation
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed 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.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* The Blowfish block cipher was designed by Bruce Schneier in 1993.
* http://www.schneier.com/blowfish.html
* http://en.wikipedia.org/wiki/Blowfish_%28cipher%29
*
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_BLOWFISH_C)
#include "mbedtls/blowfish.h"
#include <string.h>
#if !defined(MBEDTLS_BLOWFISH_ALT)
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n ) {
volatile unsigned char *p = v; while( n-- ) *p++ = 0;
}
/*
* 32-bit integer manipulation macros (big endian)
*/
#ifndef GET_UINT32_BE
#define GET_UINT32_BE(n,b,i) \
{ \
(n) = ( (uint32_t) (b)[(i) ] << 24 ) \
| ( (uint32_t) (b)[(i) + 1] << 16 ) \
| ( (uint32_t) (b)[(i) + 2] << 8 ) \
| ( (uint32_t) (b)[(i) + 3] ); \
}
#endif
#ifndef PUT_UINT32_BE
#define PUT_UINT32_BE(n,b,i) \
{ \
(b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
(b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
(b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
(b)[(i) + 3] = (unsigned char) ( (n) ); \
}
#endif
static const uint32_t P[MBEDTLS_BLOWFISH_ROUNDS + 2] = {
0x243F6A88L, 0x85A308D3L, 0x13198A2EL, 0x03707344L,
0xA4093822L, 0x299F31D0L, 0x082EFA98L, 0xEC4E6C89L,
0x452821E6L, 0x38D01377L, 0xBE5466CFL, 0x34E90C6CL,
0xC0AC29B7L, 0xC97C50DDL, 0x3F84D5B5L, 0xB5470917L,
0x9216D5D9L, 0x8979FB1BL
};
/* declarations of data at the end of this file */
static const uint32_t S[4][256];
static uint32_t F( mbedtls_blowfish_context *ctx, uint32_t x )
{
unsigned short a, b, c, d;
uint32_t y;
d = (unsigned short)(x & 0xFF);
x >>= 8;
c = (unsigned short)(x & 0xFF);
x >>= 8;
b = (unsigned short)(x & 0xFF);
x >>= 8;
a = (unsigned short)(x & 0xFF);
y = ctx->S[0][a] + ctx->S[1][b];
y = y ^ ctx->S[2][c];
y = y + ctx->S[3][d];
return( y );
}
static void blowfish_enc( mbedtls_blowfish_context *ctx, uint32_t *xl, uint32_t *xr )
{
uint32_t Xl, Xr, temp;
short i;
Xl = *xl;
Xr = *xr;
for( i = 0; i < MBEDTLS_BLOWFISH_ROUNDS; ++i )
{
Xl = Xl ^ ctx->P[i];
Xr = F( ctx, Xl ) ^ Xr;
temp = Xl;
Xl = Xr;
Xr = temp;
}
temp = Xl;
Xl = Xr;
Xr = temp;
Xr = Xr ^ ctx->P[MBEDTLS_BLOWFISH_ROUNDS];
Xl = Xl ^ ctx->P[MBEDTLS_BLOWFISH_ROUNDS + 1];
*xl = Xl;
*xr = Xr;
}
static void blowfish_dec( mbedtls_blowfish_context *ctx, uint32_t *xl, uint32_t *xr )
{
uint32_t Xl, Xr, temp;
short i;
Xl = *xl;
Xr = *xr;
for( i = MBEDTLS_BLOWFISH_ROUNDS + 1; i > 1; --i )
{
Xl = Xl ^ ctx->P[i];
Xr = F( ctx, Xl ) ^ Xr;
temp = Xl;
Xl = Xr;
Xr = temp;
}
temp = Xl;
Xl = Xr;
Xr = temp;
Xr = Xr ^ ctx->P[1];
Xl = Xl ^ ctx->P[0];
*xl = Xl;
*xr = Xr;
}
void mbedtls_blowfish_init( mbedtls_blowfish_context *ctx )
{
memset( ctx, 0, sizeof( mbedtls_blowfish_context ) );
}
void mbedtls_blowfish_free( mbedtls_blowfish_context *ctx )
{
if( ctx == NULL )
return;
mbedtls_zeroize( ctx, sizeof( mbedtls_blowfish_context ) );
}
/*
* Blowfish key schedule
*/
int mbedtls_blowfish_setkey( mbedtls_blowfish_context *ctx, const unsigned char *key,
unsigned int keybits )
{
unsigned int i, j, k;
uint32_t data, datal, datar;
if( keybits < MBEDTLS_BLOWFISH_MIN_KEY_BITS || keybits > MBEDTLS_BLOWFISH_MAX_KEY_BITS ||
( keybits % 8 ) )
{
return( MBEDTLS_ERR_BLOWFISH_INVALID_KEY_LENGTH );
}
keybits >>= 3;
for( i = 0; i < 4; i++ )
{
for( j = 0; j < 256; j++ )
ctx->S[i][j] = S[i][j];
}
j = 0;
for( i = 0; i < MBEDTLS_BLOWFISH_ROUNDS + 2; ++i )
{
data = 0x00000000;
for( k = 0; k < 4; ++k )
{
data = ( data << 8 ) | key[j++];
if( j >= keybits )
j = 0;
}
ctx->P[i] = P[i] ^ data;
}
datal = 0x00000000;
datar = 0x00000000;
for( i = 0; i < MBEDTLS_BLOWFISH_ROUNDS + 2; i += 2 )
{
blowfish_enc( ctx, &datal, &datar );
ctx->P[i] = datal;
ctx->P[i + 1] = datar;
}
for( i = 0; i < 4; i++ )
{
for( j = 0; j < 256; j += 2 )
{
blowfish_enc( ctx, &datal, &datar );
ctx->S[i][j] = datal;
ctx->S[i][j + 1] = datar;
}
}
return( 0 );
}
/*
* Blowfish-ECB block encryption/decryption
*/
int mbedtls_blowfish_crypt_ecb( mbedtls_blowfish_context *ctx,
int mode,
const unsigned char input[MBEDTLS_BLOWFISH_BLOCKSIZE],
unsigned char output[MBEDTLS_BLOWFISH_BLOCKSIZE] )
{
uint32_t X0, X1;
GET_UINT32_BE( X0, input, 0 );
GET_UINT32_BE( X1, input, 4 );
if( mode == MBEDTLS_BLOWFISH_DECRYPT )
{
blowfish_dec( ctx, &X0, &X1 );
}
else /* MBEDTLS_BLOWFISH_ENCRYPT */
{
blowfish_enc( ctx, &X0, &X1 );
}
PUT_UINT32_BE( X0, output, 0 );
PUT_UINT32_BE( X1, output, 4 );
return( 0 );
}
#if defined(MBEDTLS_CIPHER_MODE_CBC)
/*
* Blowfish-CBC buffer encryption/decryption
*/
int mbedtls_blowfish_crypt_cbc( mbedtls_blowfish_context *ctx,
int mode,
size_t length,
unsigned char iv[MBEDTLS_BLOWFISH_BLOCKSIZE],
const unsigned char *input,
unsigned char *output )
{
int i;
unsigned char temp[MBEDTLS_BLOWFISH_BLOCKSIZE];
if( length % MBEDTLS_BLOWFISH_BLOCKSIZE )
return( MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH );
if( mode == MBEDTLS_BLOWFISH_DECRYPT )
{
while( length > 0 )
{
memcpy( temp, input, MBEDTLS_BLOWFISH_BLOCKSIZE );
mbedtls_blowfish_crypt_ecb( ctx, mode, input, output );
for( i = 0; i < MBEDTLS_BLOWFISH_BLOCKSIZE;i++ )
output[i] = (unsigned char)( output[i] ^ iv[i] );
memcpy( iv, temp, MBEDTLS_BLOWFISH_BLOCKSIZE );
input += MBEDTLS_BLOWFISH_BLOCKSIZE;
output += MBEDTLS_BLOWFISH_BLOCKSIZE;
length -= MBEDTLS_BLOWFISH_BLOCKSIZE;
}
}
else
{
while( length > 0 )
{
for( i = 0; i < MBEDTLS_BLOWFISH_BLOCKSIZE; i++ )
output[i] = (unsigned char)( input[i] ^ iv[i] );
mbedtls_blowfish_crypt_ecb( ctx, mode, output, output );
memcpy( iv, output, MBEDTLS_BLOWFISH_BLOCKSIZE );
input += MBEDTLS_BLOWFISH_BLOCKSIZE;
output += MBEDTLS_BLOWFISH_BLOCKSIZE;
length -= MBEDTLS_BLOWFISH_BLOCKSIZE;
}
}
return( 0 );
}
#endif /* MBEDTLS_CIPHER_MODE_CBC */
#if defined(MBEDTLS_CIPHER_MODE_CFB)
/*
* Blowfish CFB buffer encryption/decryption
*/
int mbedtls_blowfish_crypt_cfb64( mbedtls_blowfish_context *ctx,
int mode,
size_t length,
size_t *iv_off,
unsigned char iv[MBEDTLS_BLOWFISH_BLOCKSIZE],
const unsigned char *input,
unsigned char *output )
{
int c;
size_t n = *iv_off;
if( mode == MBEDTLS_BLOWFISH_DECRYPT )
{
while( length-- )
{
if( n == 0 )
mbedtls_blowfish_crypt_ecb( ctx, MBEDTLS_BLOWFISH_ENCRYPT, iv, iv );
c = *input++;
*output++ = (unsigned char)( c ^ iv[n] );
iv[n] = (unsigned char) c;
n = ( n + 1 ) % MBEDTLS_BLOWFISH_BLOCKSIZE;
}
}
else
{
while( length-- )
{
if( n == 0 )
mbedtls_blowfish_crypt_ecb( ctx, MBEDTLS_BLOWFISH_ENCRYPT, iv, iv );
iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ );
n = ( n + 1 ) % MBEDTLS_BLOWFISH_BLOCKSIZE;
}
}
*iv_off = n;
return( 0 );
}
#endif /*MBEDTLS_CIPHER_MODE_CFB */
#if defined(MBEDTLS_CIPHER_MODE_CTR)
/*
* Blowfish CTR buffer encryption/decryption
*/
int mbedtls_blowfish_crypt_ctr( mbedtls_blowfish_context *ctx,
size_t length,
size_t *nc_off,
unsigned char nonce_counter[MBEDTLS_BLOWFISH_BLOCKSIZE],
unsigned char stream_block[MBEDTLS_BLOWFISH_BLOCKSIZE],
const unsigned char *input,
unsigned char *output )
{
int c, i;
size_t n = *nc_off;
while( length-- )
{
if( n == 0 ) {
mbedtls_blowfish_crypt_ecb( ctx, MBEDTLS_BLOWFISH_ENCRYPT, nonce_counter,
stream_block );
for( i = MBEDTLS_BLOWFISH_BLOCKSIZE; i > 0; i-- )
if( ++nonce_counter[i - 1] != 0 )
break;
}
c = *input++;
*output++ = (unsigned char)( c ^ stream_block[n] );
n = ( n + 1 ) % MBEDTLS_BLOWFISH_BLOCKSIZE;
}
*nc_off = n;
return( 0 );
}
#endif /* MBEDTLS_CIPHER_MODE_CTR */
static const uint32_t S[4][256] = {
{ 0xD1310BA6L, 0x98DFB5ACL, 0x2FFD72DBL, 0xD01ADFB7L,
0xB8E1AFEDL, 0x6A267E96L, 0xBA7C9045L, 0xF12C7F99L,
0x24A19947L, 0xB3916CF7L, 0x0801F2E2L, 0x858EFC16L,
0x636920D8L, 0x71574E69L, 0xA458FEA3L, 0xF4933D7EL,
0x0D95748FL, 0x728EB658L, 0x718BCD58L, 0x82154AEEL,
0x7B54A41DL, 0xC25A59B5L, 0x9C30D539L, 0x2AF26013L,
0xC5D1B023L, 0x286085F0L, 0xCA417918L, 0xB8DB38EFL,
0x8E79DCB0L, 0x603A180EL, 0x6C9E0E8BL, 0xB01E8A3EL,
0xD71577C1L, 0xBD314B27L, 0x78AF2FDAL, 0x55605C60L,
0xE65525F3L, 0xAA55AB94L, 0x57489862L, 0x63E81440L,
0x55CA396AL, 0x2AAB10B6L, 0xB4CC5C34L, 0x1141E8CEL,
0xA15486AFL, 0x7C72E993L, 0xB3EE1411L, 0x636FBC2AL,
0x2BA9C55DL, 0x741831F6L, 0xCE5C3E16L, 0x9B87931EL,
0xAFD6BA33L, 0x6C24CF5CL, 0x7A325381L, 0x28958677L,
0x3B8F4898L, 0x6B4BB9AFL, 0xC4BFE81BL, 0x66282193L,
0x61D809CCL, 0xFB21A991L, 0x487CAC60L, 0x5DEC8032L,
0xEF845D5DL, 0xE98575B1L, 0xDC262302L, 0xEB651B88L,
0x23893E81L, 0xD396ACC5L, 0x0F6D6FF3L, 0x83F44239L,
0x2E0B4482L, 0xA4842004L, 0x69C8F04AL, 0x9E1F9B5EL,
0x21C66842L, 0xF6E96C9AL, 0x670C9C61L, 0xABD388F0L,
0x6A51A0D2L, 0xD8542F68L, 0x960FA728L, 0xAB5133A3L,
0x6EEF0B6CL, 0x137A3BE4L, 0xBA3BF050L, 0x7EFB2A98L,
0xA1F1651DL, 0x39AF0176L, 0x66CA593EL, 0x82430E88L,
0x8CEE8619L, 0x456F9FB4L, 0x7D84A5C3L, 0x3B8B5EBEL,
0xE06F75D8L, 0x85C12073L, 0x401A449FL, 0x56C16AA6L,
0x4ED3AA62L, 0x363F7706L, 0x1BFEDF72L, 0x429B023DL,
0x37D0D724L, 0xD00A1248L, 0xDB0FEAD3L, 0x49F1C09BL,
0x075372C9L, 0x80991B7BL, 0x25D479D8L, 0xF6E8DEF7L,
0xE3FE501AL, 0xB6794C3BL, 0x976CE0BDL, 0x04C006BAL,
0xC1A94FB6L, 0x409F60C4L, 0x5E5C9EC2L, 0x196A2463L,
0x68FB6FAFL, 0x3E6C53B5L, 0x1339B2EBL, 0x3B52EC6FL,
0x6DFC511FL, 0x9B30952CL, 0xCC814544L, 0xAF5EBD09L,
0xBEE3D004L, 0xDE334AFDL, 0x660F2807L, 0x192E4BB3L,
0xC0CBA857L, 0x45C8740FL, 0xD20B5F39L, 0xB9D3FBDBL,
0x5579C0BDL, 0x1A60320AL, 0xD6A100C6L, 0x402C7279L,
0x679F25FEL, 0xFB1FA3CCL, 0x8EA5E9F8L, 0xDB3222F8L,
0x3C7516DFL, 0xFD616B15L, 0x2F501EC8L, 0xAD0552ABL,
0x323DB5FAL, 0xFD238760L, 0x53317B48L, 0x3E00DF82L,
0x9E5C57BBL, 0xCA6F8CA0L, 0x1A87562EL, 0xDF1769DBL,
0xD542A8F6L, 0x287EFFC3L, 0xAC6732C6L, 0x8C4F5573L,
0x695B27B0L, 0xBBCA58C8L, 0xE1FFA35DL, 0xB8F011A0L,
0x10FA3D98L, 0xFD2183B8L, 0x4AFCB56CL, 0x2DD1D35BL,
0x9A53E479L, 0xB6F84565L, 0xD28E49BCL, 0x4BFB9790L,
0xE1DDF2DAL, 0xA4CB7E33L, 0x62FB1341L, 0xCEE4C6E8L,
0xEF20CADAL, 0x36774C01L, 0xD07E9EFEL, 0x2BF11FB4L,
0x95DBDA4DL, 0xAE909198L, 0xEAAD8E71L, 0x6B93D5A0L,
0xD08ED1D0L, 0xAFC725E0L, 0x8E3C5B2FL, 0x8E7594B7L,
0x8FF6E2FBL, 0xF2122B64L, 0x8888B812L, 0x900DF01CL,
0x4FAD5EA0L, 0x688FC31CL, 0xD1CFF191L, 0xB3A8C1ADL,
0x2F2F2218L, 0xBE0E1777L, 0xEA752DFEL, 0x8B021FA1L,
0xE5A0CC0FL, 0xB56F74E8L, 0x18ACF3D6L, 0xCE89E299L,
0xB4A84FE0L, 0xFD13E0B7L, 0x7CC43B81L, 0xD2ADA8D9L,
0x165FA266L, 0x80957705L, 0x93CC7314L, 0x211A1477L,
0xE6AD2065L, 0x77B5FA86L, 0xC75442F5L, 0xFB9D35CFL,
0xEBCDAF0CL, 0x7B3E89A0L, 0xD6411BD3L, 0xAE1E7E49L,
0x00250E2DL, 0x2071B35EL, 0x226800BBL, 0x57B8E0AFL,
0x2464369BL, 0xF009B91EL, 0x5563911DL, 0x59DFA6AAL,
0x78C14389L, 0xD95A537FL, 0x207D5BA2L, 0x02E5B9C5L,
0x83260376L, 0x6295CFA9L, 0x11C81968L, 0x4E734A41L,
0xB3472DCAL, 0x7B14A94AL, 0x1B510052L, 0x9A532915L,
0xD60F573FL, 0xBC9BC6E4L, 0x2B60A476L, 0x81E67400L,
0x08BA6FB5L, 0x571BE91FL, 0xF296EC6BL, 0x2A0DD915L,
0xB6636521L, 0xE7B9F9B6L, 0xFF34052EL, 0xC5855664L,
0x53B02D5DL, 0xA99F8FA1L, 0x08BA4799L, 0x6E85076AL },
{ 0x4B7A70E9L, 0xB5B32944L, 0xDB75092EL, 0xC4192623L,
0xAD6EA6B0L, 0x49A7DF7DL, 0x9CEE60B8L, 0x8FEDB266L,
0xECAA8C71L, 0x699A17FFL, 0x5664526CL, 0xC2B19EE1L,
0x193602A5L, 0x75094C29L, 0xA0591340L, 0xE4183A3EL,
0x3F54989AL, 0x5B429D65L, 0x6B8FE4D6L, 0x99F73FD6L,
0xA1D29C07L, 0xEFE830F5L, 0x4D2D38E6L, 0xF0255DC1L,
0x4CDD2086L, 0x8470EB26L, 0x6382E9C6L, 0x021ECC5EL,
0x09686B3FL, 0x3EBAEFC9L, 0x3C971814L, 0x6B6A70A1L,
0x687F3584L, 0x52A0E286L, 0xB79C5305L, 0xAA500737L,
0x3E07841CL, 0x7FDEAE5CL, 0x8E7D44ECL, 0x5716F2B8L,
0xB03ADA37L, 0xF0500C0DL, 0xF01C1F04L, 0x0200B3FFL,
0xAE0CF51AL, 0x3CB574B2L, 0x25837A58L, 0xDC0921BDL,
0xD19113F9L, 0x7CA92FF6L, 0x94324773L, 0x22F54701L,
0x3AE5E581L, 0x37C2DADCL, 0xC8B57634L, 0x9AF3DDA7L,
0xA9446146L, 0x0FD0030EL, 0xECC8C73EL, 0xA4751E41L,
0xE238CD99L, 0x3BEA0E2FL, 0x3280BBA1L, 0x183EB331L,
0x4E548B38L, 0x4F6DB908L, 0x6F420D03L, 0xF60A04BFL,
0x2CB81290L, 0x24977C79L, 0x5679B072L, 0xBCAF89AFL,
0xDE9A771FL, 0xD9930810L, 0xB38BAE12L, 0xDCCF3F2EL,
0x5512721FL, 0x2E6B7124L, 0x501ADDE6L, 0x9F84CD87L,
0x7A584718L, 0x7408DA17L, 0xBC9F9ABCL, 0xE94B7D8CL,
0xEC7AEC3AL, 0xDB851DFAL, 0x63094366L, 0xC464C3D2L,
0xEF1C1847L, 0x3215D908L, 0xDD433B37L, 0x24C2BA16L,
0x12A14D43L, 0x2A65C451L, 0x50940002L, 0x133AE4DDL,
0x71DFF89EL, 0x10314E55L, 0x81AC77D6L, 0x5F11199BL,
0x043556F1L, 0xD7A3C76BL, 0x3C11183BL, 0x5924A509L,
0xF28FE6EDL, 0x97F1FBFAL, 0x9EBABF2CL, 0x1E153C6EL,
0x86E34570L, 0xEAE96FB1L, 0x860E5E0AL, 0x5A3E2AB3L,
0x771FE71CL, 0x4E3D06FAL, 0x2965DCB9L, 0x99E71D0FL,
0x803E89D6L, 0x5266C825L, 0x2E4CC978L, 0x9C10B36AL,
0xC6150EBAL, 0x94E2EA78L, 0xA5FC3C53L, 0x1E0A2DF4L,
0xF2F74EA7L, 0x361D2B3DL, 0x1939260FL, 0x19C27960L,
0x5223A708L, 0xF71312B6L, 0xEBADFE6EL, 0xEAC31F66L,
0xE3BC4595L, 0xA67BC883L, 0xB17F37D1L, 0x018CFF28L,
0xC332DDEFL, 0xBE6C5AA5L, 0x65582185L, 0x68AB9802L,
0xEECEA50FL, 0xDB2F953BL, 0x2AEF7DADL, 0x5B6E2F84L,
0x1521B628L, 0x29076170L, 0xECDD4775L, 0x619F1510L,
0x13CCA830L, 0xEB61BD96L, 0x0334FE1EL, 0xAA0363CFL,
0xB5735C90L, 0x4C70A239L, 0xD59E9E0BL, 0xCBAADE14L,
0xEECC86BCL, 0x60622CA7L, 0x9CAB5CABL, 0xB2F3846EL,
0x648B1EAFL, 0x19BDF0CAL, 0xA02369B9L, 0x655ABB50L,
0x40685A32L, 0x3C2AB4B3L, 0x319EE9D5L, 0xC021B8F7L,
0x9B540B19L, 0x875FA099L, 0x95F7997EL, 0x623D7DA8L,
0xF837889AL, 0x97E32D77L, 0x11ED935FL, 0x16681281L,
0x0E358829L, 0xC7E61FD6L, 0x96DEDFA1L, 0x7858BA99L,
0x57F584A5L, 0x1B227263L, 0x9B83C3FFL, 0x1AC24696L,
0xCDB30AEBL, 0x532E3054L, 0x8FD948E4L, 0x6DBC3128L,
0x58EBF2EFL, 0x34C6FFEAL, 0xFE28ED61L, 0xEE7C3C73L,
0x5D4A14D9L, 0xE864B7E3L, 0x42105D14L, 0x203E13E0L,
0x45EEE2B6L, 0xA3AAABEAL, 0xDB6C4F15L, 0xFACB4FD0L,
0xC742F442L, 0xEF6ABBB5L, 0x654F3B1DL, 0x41CD2105L,
0xD81E799EL, 0x86854DC7L, 0xE44B476AL, 0x3D816250L,
0xCF62A1F2L, 0x5B8D2646L, 0xFC8883A0L, 0xC1C7B6A3L,
0x7F1524C3L, 0x69CB7492L, 0x47848A0BL, 0x5692B285L,
0x095BBF00L, 0xAD19489DL, 0x1462B174L, 0x23820E00L,
0x58428D2AL, 0x0C55F5EAL, 0x1DADF43EL, 0x233F7061L,
0x3372F092L, 0x8D937E41L, 0xD65FECF1L, 0x6C223BDBL,
0x7CDE3759L, 0xCBEE7460L, 0x4085F2A7L, 0xCE77326EL,
0xA6078084L, 0x19F8509EL, 0xE8EFD855L, 0x61D99735L,
0xA969A7AAL, 0xC50C06C2L, 0x5A04ABFCL, 0x800BCADCL,
0x9E447A2EL, 0xC3453484L, 0xFDD56705L, 0x0E1E9EC9L,
0xDB73DBD3L, 0x105588CDL, 0x675FDA79L, 0xE3674340L,
0xC5C43465L, 0x713E38D8L, 0x3D28F89EL, 0xF16DFF20L,
0x153E21E7L, 0x8FB03D4AL, 0xE6E39F2BL, 0xDB83ADF7L },
{ 0xE93D5A68L, 0x948140F7L, 0xF64C261CL, 0x94692934L,
0x411520F7L, 0x7602D4F7L, 0xBCF46B2EL, 0xD4A20068L,
0xD4082471L, 0x3320F46AL, 0x43B7D4B7L, 0x500061AFL,
0x1E39F62EL, 0x97244546L, 0x14214F74L, 0xBF8B8840L,
0x4D95FC1DL, 0x96B591AFL, 0x70F4DDD3L, 0x66A02F45L,
0xBFBC09ECL, 0x03BD9785L, 0x7FAC6DD0L, 0x31CB8504L,
0x96EB27B3L, 0x55FD3941L, 0xDA2547E6L, 0xABCA0A9AL,
0x28507825L, 0x530429F4L, 0x0A2C86DAL, 0xE9B66DFBL,
0x68DC1462L, 0xD7486900L, 0x680EC0A4L, 0x27A18DEEL,
0x4F3FFEA2L, 0xE887AD8CL, 0xB58CE006L, 0x7AF4D6B6L,
0xAACE1E7CL, 0xD3375FECL, 0xCE78A399L, 0x406B2A42L,
0x20FE9E35L, 0xD9F385B9L, 0xEE39D7ABL, 0x3B124E8BL,
0x1DC9FAF7L, 0x4B6D1856L, 0x26A36631L, 0xEAE397B2L,
0x3A6EFA74L, 0xDD5B4332L, 0x6841E7F7L, 0xCA7820FBL,
0xFB0AF54EL, 0xD8FEB397L, 0x454056ACL, 0xBA489527L,
0x55533A3AL, 0x20838D87L, 0xFE6BA9B7L, 0xD096954BL,
0x55A867BCL, 0xA1159A58L, 0xCCA92963L, 0x99E1DB33L,
0xA62A4A56L, 0x3F3125F9L, 0x5EF47E1CL, 0x9029317CL,
0xFDF8E802L, 0x04272F70L, 0x80BB155CL, 0x05282CE3L,
0x95C11548L, 0xE4C66D22L, 0x48C1133FL, 0xC70F86DCL,
0x07F9C9EEL, 0x41041F0FL, 0x404779A4L, 0x5D886E17L,
0x325F51EBL, 0xD59BC0D1L, 0xF2BCC18FL, 0x41113564L,
0x257B7834L, 0x602A9C60L, 0xDFF8E8A3L, 0x1F636C1BL,
0x0E12B4C2L, 0x02E1329EL, 0xAF664FD1L, 0xCAD18115L,
0x6B2395E0L, 0x333E92E1L, 0x3B240B62L, 0xEEBEB922L,
0x85B2A20EL, 0xE6BA0D99L, 0xDE720C8CL, 0x2DA2F728L,
0xD0127845L, 0x95B794FDL, 0x647D0862L, 0xE7CCF5F0L,
0x5449A36FL, 0x877D48FAL, 0xC39DFD27L, 0xF33E8D1EL,
0x0A476341L, 0x992EFF74L, 0x3A6F6EABL, 0xF4F8FD37L,
0xA812DC60L, 0xA1EBDDF8L, 0x991BE14CL, 0xDB6E6B0DL,
0xC67B5510L, 0x6D672C37L, 0x2765D43BL, 0xDCD0E804L,
0xF1290DC7L, 0xCC00FFA3L, 0xB5390F92L, 0x690FED0BL,
0x667B9FFBL, 0xCEDB7D9CL, 0xA091CF0BL, 0xD9155EA3L,
0xBB132F88L, 0x515BAD24L, 0x7B9479BFL, 0x763BD6EBL,
0x37392EB3L, 0xCC115979L, 0x8026E297L, 0xF42E312DL,
0x6842ADA7L, 0xC66A2B3BL, 0x12754CCCL, 0x782EF11CL,
0x6A124237L, 0xB79251E7L, 0x06A1BBE6L, 0x4BFB6350L,
0x1A6B1018L, 0x11CAEDFAL, 0x3D25BDD8L, 0xE2E1C3C9L,
0x44421659L, 0x0A121386L, 0xD90CEC6EL, 0xD5ABEA2AL,
0x64AF674EL, 0xDA86A85FL, 0xBEBFE988L, 0x64E4C3FEL,
0x9DBC8057L, 0xF0F7C086L, 0x60787BF8L, 0x6003604DL,
0xD1FD8346L, 0xF6381FB0L, 0x7745AE04L, 0xD736FCCCL,
0x83426B33L, 0xF01EAB71L, 0xB0804187L, 0x3C005E5FL,
0x77A057BEL, 0xBDE8AE24L, 0x55464299L, 0xBF582E61L,
0x4E58F48FL, 0xF2DDFDA2L, 0xF474EF38L, 0x8789BDC2L,
0x5366F9C3L, 0xC8B38E74L, 0xB475F255L, 0x46FCD9B9L,
0x7AEB2661L, 0x8B1DDF84L, 0x846A0E79L, 0x915F95E2L,
0x466E598EL, 0x20B45770L, 0x8CD55591L, 0xC902DE4CL,
0xB90BACE1L, 0xBB8205D0L, 0x11A86248L, 0x7574A99EL,
0xB77F19B6L, 0xE0A9DC09L, 0x662D09A1L, 0xC4324633L,
0xE85A1F02L, 0x09F0BE8CL, 0x4A99A025L, 0x1D6EFE10L,
0x1AB93D1DL, 0x0BA5A4DFL, 0xA186F20FL, 0x2868F169L,
0xDCB7DA83L, 0x573906FEL, 0xA1E2CE9BL, 0x4FCD7F52L,
0x50115E01L, 0xA70683FAL, 0xA002B5C4L, 0x0DE6D027L,
0x9AF88C27L, 0x773F8641L, 0xC3604C06L, 0x61A806B5L,
0xF0177A28L, 0xC0F586E0L, 0x006058AAL, 0x30DC7D62L,
0x11E69ED7L, 0x2338EA63L, 0x53C2DD94L, 0xC2C21634L,
0xBBCBEE56L, 0x90BCB6DEL, 0xEBFC7DA1L, 0xCE591D76L,
0x6F05E409L, 0x4B7C0188L, 0x39720A3DL, 0x7C927C24L,
0x86E3725FL, 0x724D9DB9L, 0x1AC15BB4L, 0xD39EB8FCL,
0xED545578L, 0x08FCA5B5L, 0xD83D7CD3L, 0x4DAD0FC4L,
0x1E50EF5EL, 0xB161E6F8L, 0xA28514D9L, 0x6C51133CL,
0x6FD5C7E7L, 0x56E14EC4L, 0x362ABFCEL, 0xDDC6C837L,
0xD79A3234L, 0x92638212L, 0x670EFA8EL, 0x406000E0L },
{ 0x3A39CE37L, 0xD3FAF5CFL, 0xABC27737L, 0x5AC52D1BL,
0x5CB0679EL, 0x4FA33742L, 0xD3822740L, 0x99BC9BBEL,
0xD5118E9DL, 0xBF0F7315L, 0xD62D1C7EL, 0xC700C47BL,
0xB78C1B6BL, 0x21A19045L, 0xB26EB1BEL, 0x6A366EB4L,
0x5748AB2FL, 0xBC946E79L, 0xC6A376D2L, 0x6549C2C8L,
0x530FF8EEL, 0x468DDE7DL, 0xD5730A1DL, 0x4CD04DC6L,
0x2939BBDBL, 0xA9BA4650L, 0xAC9526E8L, 0xBE5EE304L,
0xA1FAD5F0L, 0x6A2D519AL, 0x63EF8CE2L, 0x9A86EE22L,
0xC089C2B8L, 0x43242EF6L, 0xA51E03AAL, 0x9CF2D0A4L,
0x83C061BAL, 0x9BE96A4DL, 0x8FE51550L, 0xBA645BD6L,
0x2826A2F9L, 0xA73A3AE1L, 0x4BA99586L, 0xEF5562E9L,
0xC72FEFD3L, 0xF752F7DAL, 0x3F046F69L, 0x77FA0A59L,
0x80E4A915L, 0x87B08601L, 0x9B09E6ADL, 0x3B3EE593L,
0xE990FD5AL, 0x9E34D797L, 0x2CF0B7D9L, 0x022B8B51L,
0x96D5AC3AL, 0x017DA67DL, 0xD1CF3ED6L, 0x7C7D2D28L,
0x1F9F25CFL, 0xADF2B89BL, 0x5AD6B472L, 0x5A88F54CL,
0xE029AC71L, 0xE019A5E6L, 0x47B0ACFDL, 0xED93FA9BL,
0xE8D3C48DL, 0x283B57CCL, 0xF8D56629L, 0x79132E28L,
0x785F0191L, 0xED756055L, 0xF7960E44L, 0xE3D35E8CL,
0x15056DD4L, 0x88F46DBAL, 0x03A16125L, 0x0564F0BDL,
0xC3EB9E15L, 0x3C9057A2L, 0x97271AECL, 0xA93A072AL,
0x1B3F6D9BL, 0x1E6321F5L, 0xF59C66FBL, 0x26DCF319L,
0x7533D928L, 0xB155FDF5L, 0x03563482L, 0x8ABA3CBBL,
0x28517711L, 0xC20AD9F8L, 0xABCC5167L, 0xCCAD925FL,
0x4DE81751L, 0x3830DC8EL, 0x379D5862L, 0x9320F991L,
0xEA7A90C2L, 0xFB3E7BCEL, 0x5121CE64L, 0x774FBE32L,
0xA8B6E37EL, 0xC3293D46L, 0x48DE5369L, 0x6413E680L,
0xA2AE0810L, 0xDD6DB224L, 0x69852DFDL, 0x09072166L,
0xB39A460AL, 0x6445C0DDL, 0x586CDECFL, 0x1C20C8AEL,
0x5BBEF7DDL, 0x1B588D40L, 0xCCD2017FL, 0x6BB4E3BBL,
0xDDA26A7EL, 0x3A59FF45L, 0x3E350A44L, 0xBCB4CDD5L,
0x72EACEA8L, 0xFA6484BBL, 0x8D6612AEL, 0xBF3C6F47L,
0xD29BE463L, 0x542F5D9EL, 0xAEC2771BL, 0xF64E6370L,
0x740E0D8DL, 0xE75B1357L, 0xF8721671L, 0xAF537D5DL,
0x4040CB08L, 0x4EB4E2CCL, 0x34D2466AL, 0x0115AF84L,
0xE1B00428L, 0x95983A1DL, 0x06B89FB4L, 0xCE6EA048L,
0x6F3F3B82L, 0x3520AB82L, 0x011A1D4BL, 0x277227F8L,
0x611560B1L, 0xE7933FDCL, 0xBB3A792BL, 0x344525BDL,
0xA08839E1L, 0x51CE794BL, 0x2F32C9B7L, 0xA01FBAC9L,
0xE01CC87EL, 0xBCC7D1F6L, 0xCF0111C3L, 0xA1E8AAC7L,
0x1A908749L, 0xD44FBD9AL, 0xD0DADECBL, 0xD50ADA38L,
0x0339C32AL, 0xC6913667L, 0x8DF9317CL, 0xE0B12B4FL,
0xF79E59B7L, 0x43F5BB3AL, 0xF2D519FFL, 0x27D9459CL,
0xBF97222CL, 0x15E6FC2AL, 0x0F91FC71L, 0x9B941525L,
0xFAE59361L, 0xCEB69CEBL, 0xC2A86459L, 0x12BAA8D1L,
0xB6C1075EL, 0xE3056A0CL, 0x10D25065L, 0xCB03A442L,
0xE0EC6E0EL, 0x1698DB3BL, 0x4C98A0BEL, 0x3278E964L,
0x9F1F9532L, 0xE0D392DFL, 0xD3A0342BL, 0x8971F21EL,
0x1B0A7441L, 0x4BA3348CL, 0xC5BE7120L, 0xC37632D8L,
0xDF359F8DL, 0x9B992F2EL, 0xE60B6F47L, 0x0FE3F11DL,
0xE54CDA54L, 0x1EDAD891L, 0xCE6279CFL, 0xCD3E7E6FL,
0x1618B166L, 0xFD2C1D05L, 0x848FD2C5L, 0xF6FB2299L,
0xF523F357L, 0xA6327623L, 0x93A83531L, 0x56CCCD02L,
0xACF08162L, 0x5A75EBB5L, 0x6E163697L, 0x88D273CCL,
0xDE966292L, 0x81B949D0L, 0x4C50901BL, 0x71C65614L,
0xE6C6C7BDL, 0x327A140AL, 0x45E1D006L, 0xC3F27B9AL,
0xC9AA53FDL, 0x62A80F00L, 0xBB25BFE2L, 0x35BDD2F6L,
0x71126905L, 0xB2040222L, 0xB6CBCF7CL, 0xCD769C2BL,
0x53113EC0L, 0x1640E3D3L, 0x38ABBD60L, 0x2547ADF0L,
0xBA38209CL, 0xF746CE76L, 0x77AFA1C5L, 0x20756060L,
0x85CBFE4EL, 0x8AE88DD8L, 0x7AAAF9B0L, 0x4CF9AA7EL,
0x1948C25CL, 0x02FB8A8CL, 0x01C36AE4L, 0xD6EBE1F9L,
0x90D4F869L, 0xA65CDEA0L, 0x3F09252DL, 0xC208E69FL,
0xB74E6132L, 0xCE77E25BL, 0x578FDFE3L, 0x3AC372E6L }
};
#endif /* !MBEDTLS_BLOWFISH_ALT */
#endif /* MBEDTLS_BLOWFISH_C */
/*
* Camellia implementation
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed 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.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* The Camellia block cipher was designed by NTT and Mitsubishi Electric
* Corporation.
*
* http://info.isl.ntt.co.jp/crypt/eng/camellia/dl/01espec.pdf
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_CAMELLIA_C)
#include "mbedtls/camellia.h"
#include <string.h>
#if defined(MBEDTLS_SELF_TEST)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST */
#if !defined(MBEDTLS_CAMELLIA_ALT)
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n ) {
volatile unsigned char *p = v; while( n-- ) *p++ = 0;
}
/*
* 32-bit integer manipulation macros (big endian)
*/
#ifndef GET_UINT32_BE
#define GET_UINT32_BE(n,b,i) \
{ \
(n) = ( (uint32_t) (b)[(i) ] << 24 ) \
| ( (uint32_t) (b)[(i) + 1] << 16 ) \
| ( (uint32_t) (b)[(i) + 2] << 8 ) \
| ( (uint32_t) (b)[(i) + 3] ); \
}
#endif
#ifndef PUT_UINT32_BE
#define PUT_UINT32_BE(n,b,i) \
{ \
(b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
(b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
(b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
(b)[(i) + 3] = (unsigned char) ( (n) ); \
}
#endif
static const unsigned char SIGMA_CHARS[6][8] =
{
{ 0xa0, 0x9e, 0x66, 0x7f, 0x3b, 0xcc, 0x90, 0x8b },
{ 0xb6, 0x7a, 0xe8, 0x58, 0x4c, 0xaa, 0x73, 0xb2 },
{ 0xc6, 0xef, 0x37, 0x2f, 0xe9, 0x4f, 0x82, 0xbe },
{ 0x54, 0xff, 0x53, 0xa5, 0xf1, 0xd3, 0x6f, 0x1c },
{ 0x10, 0xe5, 0x27, 0xfa, 0xde, 0x68, 0x2d, 0x1d },
{ 0xb0, 0x56, 0x88, 0xc2, 0xb3, 0xe6, 0xc1, 0xfd }
};
#if defined(MBEDTLS_CAMELLIA_SMALL_MEMORY)
static const unsigned char FSb[256] =
{
112,130, 44,236,179, 39,192,229,228,133, 87, 53,234, 12,174, 65,
35,239,107,147, 69, 25,165, 33,237, 14, 79, 78, 29,101,146,189,
134,184,175,143,124,235, 31,206, 62, 48,220, 95, 94,197, 11, 26,
166,225, 57,202,213, 71, 93, 61,217, 1, 90,214, 81, 86,108, 77,
139, 13,154,102,251,204,176, 45,116, 18, 43, 32,240,177,132,153,
223, 76,203,194, 52,126,118, 5,109,183,169, 49,209, 23, 4,215,
20, 88, 58, 97,222, 27, 17, 28, 50, 15,156, 22, 83, 24,242, 34,
254, 68,207,178,195,181,122,145, 36, 8,232,168, 96,252,105, 80,
170,208,160,125,161,137, 98,151, 84, 91, 30,149,224,255,100,210,
16,196, 0, 72,163,247,117,219,138, 3,230,218, 9, 63,221,148,
135, 92,131, 2,205, 74,144, 51,115,103,246,243,157,127,191,226,
82,155,216, 38,200, 55,198, 59,129,150,111, 75, 19,190, 99, 46,
233,121,167,140,159,110,188,142, 41,245,249,182, 47,253,180, 89,
120,152, 6,106,231, 70,113,186,212, 37,171, 66,136,162,141,250,
114, 7,185, 85,248,238,172, 10, 54, 73, 42,104, 60, 56,241,164,
64, 40,211,123,187,201, 67,193, 21,227,173,244,119,199,128,158
};
#define SBOX1(n) FSb[(n)]
#define SBOX2(n) (unsigned char)((FSb[(n)] >> 7 ^ FSb[(n)] << 1) & 0xff)
#define SBOX3(n) (unsigned char)((FSb[(n)] >> 1 ^ FSb[(n)] << 7) & 0xff)
#define SBOX4(n) FSb[((n) << 1 ^ (n) >> 7) &0xff]
#else /* MBEDTLS_CAMELLIA_SMALL_MEMORY */
static const unsigned char FSb[256] =
{
112, 130, 44, 236, 179, 39, 192, 229, 228, 133, 87, 53, 234, 12, 174, 65,
35, 239, 107, 147, 69, 25, 165, 33, 237, 14, 79, 78, 29, 101, 146, 189,
134, 184, 175, 143, 124, 235, 31, 206, 62, 48, 220, 95, 94, 197, 11, 26,
166, 225, 57, 202, 213, 71, 93, 61, 217, 1, 90, 214, 81, 86, 108, 77,
139, 13, 154, 102, 251, 204, 176, 45, 116, 18, 43, 32, 240, 177, 132, 153,
223, 76, 203, 194, 52, 126, 118, 5, 109, 183, 169, 49, 209, 23, 4, 215,
20, 88, 58, 97, 222, 27, 17, 28, 50, 15, 156, 22, 83, 24, 242, 34,
254, 68, 207, 178, 195, 181, 122, 145, 36, 8, 232, 168, 96, 252, 105, 80,
170, 208, 160, 125, 161, 137, 98, 151, 84, 91, 30, 149, 224, 255, 100, 210,
16, 196, 0, 72, 163, 247, 117, 219, 138, 3, 230, 218, 9, 63, 221, 148,
135, 92, 131, 2, 205, 74, 144, 51, 115, 103, 246, 243, 157, 127, 191, 226,
82, 155, 216, 38, 200, 55, 198, 59, 129, 150, 111, 75, 19, 190, 99, 46,
233, 121, 167, 140, 159, 110, 188, 142, 41, 245, 249, 182, 47, 253, 180, 89,
120, 152, 6, 106, 231, 70, 113, 186, 212, 37, 171, 66, 136, 162, 141, 250,
114, 7, 185, 85, 248, 238, 172, 10, 54, 73, 42, 104, 60, 56, 241, 164,
64, 40, 211, 123, 187, 201, 67, 193, 21, 227, 173, 244, 119, 199, 128, 158
};
static const unsigned char FSb2[256] =
{
224, 5, 88, 217, 103, 78, 129, 203, 201, 11, 174, 106, 213, 24, 93, 130,
70, 223, 214, 39, 138, 50, 75, 66, 219, 28, 158, 156, 58, 202, 37, 123,
13, 113, 95, 31, 248, 215, 62, 157, 124, 96, 185, 190, 188, 139, 22, 52,
77, 195, 114, 149, 171, 142, 186, 122, 179, 2, 180, 173, 162, 172, 216, 154,
23, 26, 53, 204, 247, 153, 97, 90, 232, 36, 86, 64, 225, 99, 9, 51,
191, 152, 151, 133, 104, 252, 236, 10, 218, 111, 83, 98, 163, 46, 8, 175,
40, 176, 116, 194, 189, 54, 34, 56, 100, 30, 57, 44, 166, 48, 229, 68,
253, 136, 159, 101, 135, 107, 244, 35, 72, 16, 209, 81, 192, 249, 210, 160,
85, 161, 65, 250, 67, 19, 196, 47, 168, 182, 60, 43, 193, 255, 200, 165,
32, 137, 0, 144, 71, 239, 234, 183, 21, 6, 205, 181, 18, 126, 187, 41,
15, 184, 7, 4, 155, 148, 33, 102, 230, 206, 237, 231, 59, 254, 127, 197,
164, 55, 177, 76, 145, 110, 141, 118, 3, 45, 222, 150, 38, 125, 198, 92,
211, 242, 79, 25, 63, 220, 121, 29, 82, 235, 243, 109, 94, 251, 105, 178,
240, 49, 12, 212, 207, 140, 226, 117, 169, 74, 87, 132, 17, 69, 27, 245,
228, 14, 115, 170, 241, 221, 89, 20, 108, 146, 84, 208, 120, 112, 227, 73,
128, 80, 167, 246, 119, 147, 134, 131, 42, 199, 91, 233, 238, 143, 1, 61
};
static const unsigned char FSb3[256] =
{
56, 65, 22, 118, 217, 147, 96, 242, 114, 194, 171, 154, 117, 6, 87, 160,
145, 247, 181, 201, 162, 140, 210, 144, 246, 7, 167, 39, 142, 178, 73, 222,
67, 92, 215, 199, 62, 245, 143, 103, 31, 24, 110, 175, 47, 226, 133, 13,
83, 240, 156, 101, 234, 163, 174, 158, 236, 128, 45, 107, 168, 43, 54, 166,
197, 134, 77, 51, 253, 102, 88, 150, 58, 9, 149, 16, 120, 216, 66, 204,
239, 38, 229, 97, 26, 63, 59, 130, 182, 219, 212, 152, 232, 139, 2, 235,
10, 44, 29, 176, 111, 141, 136, 14, 25, 135, 78, 11, 169, 12, 121, 17,
127, 34, 231, 89, 225, 218, 61, 200, 18, 4, 116, 84, 48, 126, 180, 40,
85, 104, 80, 190, 208, 196, 49, 203, 42, 173, 15, 202, 112, 255, 50, 105,
8, 98, 0, 36, 209, 251, 186, 237, 69, 129, 115, 109, 132, 159, 238, 74,
195, 46, 193, 1, 230, 37, 72, 153, 185, 179, 123, 249, 206, 191, 223, 113,
41, 205, 108, 19, 100, 155, 99, 157, 192, 75, 183, 165, 137, 95, 177, 23,
244, 188, 211, 70, 207, 55, 94, 71, 148, 250, 252, 91, 151, 254, 90, 172,
60, 76, 3, 53, 243, 35, 184, 93, 106, 146, 213, 33, 68, 81, 198, 125,
57, 131, 220, 170, 124, 119, 86, 5, 27, 164, 21, 52, 30, 28, 248, 82,
32, 20, 233, 189, 221, 228, 161, 224, 138, 241, 214, 122, 187, 227, 64, 79
};
static const unsigned char FSb4[256] =
{
112, 44, 179, 192, 228, 87, 234, 174, 35, 107, 69, 165, 237, 79, 29, 146,
134, 175, 124, 31, 62, 220, 94, 11, 166, 57, 213, 93, 217, 90, 81, 108,
139, 154, 251, 176, 116, 43, 240, 132, 223, 203, 52, 118, 109, 169, 209, 4,
20, 58, 222, 17, 50, 156, 83, 242, 254, 207, 195, 122, 36, 232, 96, 105,
170, 160, 161, 98, 84, 30, 224, 100, 16, 0, 163, 117, 138, 230, 9, 221,
135, 131, 205, 144, 115, 246, 157, 191, 82, 216, 200, 198, 129, 111, 19, 99,
233, 167, 159, 188, 41, 249, 47, 180, 120, 6, 231, 113, 212, 171, 136, 141,
114, 185, 248, 172, 54, 42, 60, 241, 64, 211, 187, 67, 21, 173, 119, 128,
130, 236, 39, 229, 133, 53, 12, 65, 239, 147, 25, 33, 14, 78, 101, 189,
184, 143, 235, 206, 48, 95, 197, 26, 225, 202, 71, 61, 1, 214, 86, 77,
13, 102, 204, 45, 18, 32, 177, 153, 76, 194, 126, 5, 183, 49, 23, 215,
88, 97, 27, 28, 15, 22, 24, 34, 68, 178, 181, 145, 8, 168, 252, 80,
208, 125, 137, 151, 91, 149, 255, 210, 196, 72, 247, 219, 3, 218, 63, 148,
92, 2, 74, 51, 103, 243, 127, 226, 155, 38, 55, 59, 150, 75, 190, 46,
121, 140, 110, 142, 245, 182, 253, 89, 152, 106, 70, 186, 37, 66, 162, 250,
7, 85, 238, 10, 73, 104, 56, 164, 40, 123, 201, 193, 227, 244, 199, 158
};
#define SBOX1(n) FSb[(n)]
#define SBOX2(n) FSb2[(n)]
#define SBOX3(n) FSb3[(n)]
#define SBOX4(n) FSb4[(n)]
#endif /* MBEDTLS_CAMELLIA_SMALL_MEMORY */
static const unsigned char shifts[2][4][4] =
{
{
{ 1, 1, 1, 1 }, /* KL */
{ 0, 0, 0, 0 }, /* KR */
{ 1, 1, 1, 1 }, /* KA */
{ 0, 0, 0, 0 } /* KB */
},
{
{ 1, 0, 1, 1 }, /* KL */
{ 1, 1, 0, 1 }, /* KR */
{ 1, 1, 1, 0 }, /* KA */
{ 1, 1, 0, 1 } /* KB */
}
};
static const signed char indexes[2][4][20] =
{
{
{ 0, 1, 2, 3, 8, 9, 10, 11, 38, 39,
36, 37, 23, 20, 21, 22, 27, -1, -1, 26 }, /* KL -> RK */
{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /* KR -> RK */
{ 4, 5, 6, 7, 12, 13, 14, 15, 16, 17,
18, 19, -1, 24, 25, -1, 31, 28, 29, 30 }, /* KA -> RK */
{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } /* KB -> RK */
},
{
{ 0, 1, 2, 3, 61, 62, 63, 60, -1, -1,
-1, -1, 27, 24, 25, 26, 35, 32, 33, 34 }, /* KL -> RK */
{ -1, -1, -1, -1, 8, 9, 10, 11, 16, 17,
18, 19, -1, -1, -1, -1, 39, 36, 37, 38 }, /* KR -> RK */
{ -1, -1, -1, -1, 12, 13, 14, 15, 58, 59,
56, 57, 31, 28, 29, 30, -1, -1, -1, -1 }, /* KA -> RK */
{ 4, 5, 6, 7, 65, 66, 67, 64, 20, 21,
22, 23, -1, -1, -1, -1, 43, 40, 41, 42 } /* KB -> RK */
}
};
static const signed char transposes[2][20] =
{
{
21, 22, 23, 20,
-1, -1, -1, -1,
18, 19, 16, 17,
11, 8, 9, 10,
15, 12, 13, 14
},
{
25, 26, 27, 24,
29, 30, 31, 28,
18, 19, 16, 17,
-1, -1, -1, -1,
-1, -1, -1, -1
}
};
/* Shift macro for 128 bit strings with rotation smaller than 32 bits (!) */
#define ROTL(DEST, SRC, SHIFT) \
{ \
(DEST)[0] = (SRC)[0] << (SHIFT) ^ (SRC)[1] >> (32 - (SHIFT)); \
(DEST)[1] = (SRC)[1] << (SHIFT) ^ (SRC)[2] >> (32 - (SHIFT)); \
(DEST)[2] = (SRC)[2] << (SHIFT) ^ (SRC)[3] >> (32 - (SHIFT)); \
(DEST)[3] = (SRC)[3] << (SHIFT) ^ (SRC)[0] >> (32 - (SHIFT)); \
}
#define FL(XL, XR, KL, KR) \
{ \
(XR) = ((((XL) & (KL)) << 1) | (((XL) & (KL)) >> 31)) ^ (XR); \
(XL) = ((XR) | (KR)) ^ (XL); \
}
#define FLInv(YL, YR, KL, KR) \
{ \
(YL) = ((YR) | (KR)) ^ (YL); \
(YR) = ((((YL) & (KL)) << 1) | (((YL) & (KL)) >> 31)) ^ (YR); \
}
#define SHIFT_AND_PLACE(INDEX, OFFSET) \
{ \
TK[0] = KC[(OFFSET) * 4 + 0]; \
TK[1] = KC[(OFFSET) * 4 + 1]; \
TK[2] = KC[(OFFSET) * 4 + 2]; \
TK[3] = KC[(OFFSET) * 4 + 3]; \
\
for( i = 1; i <= 4; i++ ) \
if( shifts[(INDEX)][(OFFSET)][i -1] ) \
ROTL(TK + i * 4, TK, ( 15 * i ) % 32); \
\
for( i = 0; i < 20; i++ ) \
if( indexes[(INDEX)][(OFFSET)][i] != -1 ) { \
RK[indexes[(INDEX)][(OFFSET)][i]] = TK[ i ]; \
} \
}
static void camellia_feistel( const uint32_t x[2], const uint32_t k[2],
uint32_t z[2])
{
uint32_t I0, I1;
I0 = x[0] ^ k[0];
I1 = x[1] ^ k[1];
I0 = ((uint32_t) SBOX1((I0 >> 24) & 0xFF) << 24) |
((uint32_t) SBOX2((I0 >> 16) & 0xFF) << 16) |
((uint32_t) SBOX3((I0 >> 8) & 0xFF) << 8) |
((uint32_t) SBOX4((I0 ) & 0xFF) );
I1 = ((uint32_t) SBOX2((I1 >> 24) & 0xFF) << 24) |
((uint32_t) SBOX3((I1 >> 16) & 0xFF) << 16) |
((uint32_t) SBOX4((I1 >> 8) & 0xFF) << 8) |
((uint32_t) SBOX1((I1 ) & 0xFF) );
I0 ^= (I1 << 8) | (I1 >> 24);
I1 ^= (I0 << 16) | (I0 >> 16);
I0 ^= (I1 >> 8) | (I1 << 24);
I1 ^= (I0 >> 8) | (I0 << 24);
z[0] ^= I1;
z[1] ^= I0;
}
void mbedtls_camellia_init( mbedtls_camellia_context *ctx )
{
memset( ctx, 0, sizeof( mbedtls_camellia_context ) );
}
void mbedtls_camellia_free( mbedtls_camellia_context *ctx )
{
if( ctx == NULL )
return;
mbedtls_zeroize( ctx, sizeof( mbedtls_camellia_context ) );
}
/*
* Camellia key schedule (encryption)
*/
int mbedtls_camellia_setkey_enc( mbedtls_camellia_context *ctx, const unsigned char *key,
unsigned int keybits )
{
int idx;
size_t i;
uint32_t *RK;
unsigned char t[64];
uint32_t SIGMA[6][2];
uint32_t KC[16];
uint32_t TK[20];
RK = ctx->rk;
memset( t, 0, 64 );
memset( RK, 0, sizeof(ctx->rk) );
switch( keybits )
{
case 128: ctx->nr = 3; idx = 0; break;
case 192:
case 256: ctx->nr = 4; idx = 1; break;
default : return( MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH );
}
for( i = 0; i < keybits / 8; ++i )
t[i] = key[i];
if( keybits == 192 ) {
for( i = 0; i < 8; i++ )
t[24 + i] = ~t[16 + i];
}
/*
* Prepare SIGMA values
*/
for( i = 0; i < 6; i++ ) {
GET_UINT32_BE( SIGMA[i][0], SIGMA_CHARS[i], 0 );
GET_UINT32_BE( SIGMA[i][1], SIGMA_CHARS[i], 4 );
}
/*
* Key storage in KC
* Order: KL, KR, KA, KB
*/
memset( KC, 0, sizeof(KC) );
/* Store KL, KR */
for( i = 0; i < 8; i++ )
GET_UINT32_BE( KC[i], t, i * 4 );
/* Generate KA */
for( i = 0; i < 4; ++i )
KC[8 + i] = KC[i] ^ KC[4 + i];
camellia_feistel( KC + 8, SIGMA[0], KC + 10 );
camellia_feistel( KC + 10, SIGMA[1], KC + 8 );
for( i = 0; i < 4; ++i )
KC[8 + i] ^= KC[i];
camellia_feistel( KC + 8, SIGMA[2], KC + 10 );
camellia_feistel( KC + 10, SIGMA[3], KC + 8 );
if( keybits > 128 ) {
/* Generate KB */
for( i = 0; i < 4; ++i )
KC[12 + i] = KC[4 + i] ^ KC[8 + i];
camellia_feistel( KC + 12, SIGMA[4], KC + 14 );
camellia_feistel( KC + 14, SIGMA[5], KC + 12 );
}
/*
* Generating subkeys
*/
/* Manipulating KL */
SHIFT_AND_PLACE( idx, 0 );
/* Manipulating KR */
if( keybits > 128 ) {
SHIFT_AND_PLACE( idx, 1 );
}
/* Manipulating KA */
SHIFT_AND_PLACE( idx, 2 );
/* Manipulating KB */
if( keybits > 128 ) {
SHIFT_AND_PLACE( idx, 3 );
}
/* Do transpositions */
for( i = 0; i < 20; i++ ) {
if( transposes[idx][i] != -1 ) {
RK[32 + 12 * idx + i] = RK[transposes[idx][i]];
}
}
return( 0 );
}
/*
* Camellia key schedule (decryption)
*/
int mbedtls_camellia_setkey_dec( mbedtls_camellia_context *ctx, const unsigned char *key,
unsigned int keybits )
{
int idx, ret;
size_t i;
mbedtls_camellia_context cty;
uint32_t *RK;
uint32_t *SK;
mbedtls_camellia_init( &cty );
/* Also checks keybits */
if( ( ret = mbedtls_camellia_setkey_enc( &cty, key, keybits ) ) != 0 )
goto exit;
ctx->nr = cty.nr;
idx = ( ctx->nr == 4 );
RK = ctx->rk;
SK = cty.rk + 24 * 2 + 8 * idx * 2;
*RK++ = *SK++;
*RK++ = *SK++;
*RK++ = *SK++;
*RK++ = *SK++;
for( i = 22 + 8 * idx, SK -= 6; i > 0; i--, SK -= 4 )
{
*RK++ = *SK++;
*RK++ = *SK++;
}
SK -= 2;
*RK++ = *SK++;
*RK++ = *SK++;
*RK++ = *SK++;
*RK++ = *SK++;
exit:
mbedtls_camellia_free( &cty );
return( ret );
}
/*
* Camellia-ECB block encryption/decryption
*/
int mbedtls_camellia_crypt_ecb( mbedtls_camellia_context *ctx,
int mode,
const unsigned char input[16],
unsigned char output[16] )
{
int NR;
uint32_t *RK, X[4];
( (void) mode );
NR = ctx->nr;
RK = ctx->rk;
GET_UINT32_BE( X[0], input, 0 );
GET_UINT32_BE( X[1], input, 4 );
GET_UINT32_BE( X[2], input, 8 );
GET_UINT32_BE( X[3], input, 12 );
X[0] ^= *RK++;
X[1] ^= *RK++;
X[2] ^= *RK++;
X[3] ^= *RK++;
while( NR ) {
--NR;
camellia_feistel( X, RK, X + 2 );
RK += 2;
camellia_feistel( X + 2, RK, X );
RK += 2;
camellia_feistel( X, RK, X + 2 );
RK += 2;
camellia_feistel( X + 2, RK, X );
RK += 2;
camellia_feistel( X, RK, X + 2 );
RK += 2;
camellia_feistel( X + 2, RK, X );
RK += 2;
if( NR ) {
FL(X[0], X[1], RK[0], RK[1]);
RK += 2;
FLInv(X[2], X[3], RK[0], RK[1]);
RK += 2;
}
}
X[2] ^= *RK++;
X[3] ^= *RK++;
X[0] ^= *RK++;
X[1] ^= *RK++;
PUT_UINT32_BE( X[2], output, 0 );
PUT_UINT32_BE( X[3], output, 4 );
PUT_UINT32_BE( X[0], output, 8 );
PUT_UINT32_BE( X[1], output, 12 );
return( 0 );
}
#if defined(MBEDTLS_CIPHER_MODE_CBC)
/*
* Camellia-CBC buffer encryption/decryption
*/
int mbedtls_camellia_crypt_cbc( mbedtls_camellia_context *ctx,
int mode,
size_t length,
unsigned char iv[16],
const unsigned char *input,
unsigned char *output )
{
int i;
unsigned char temp[16];
if( length % 16 )
return( MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH );
if( mode == MBEDTLS_CAMELLIA_DECRYPT )
{
while( length > 0 )
{
memcpy( temp, input, 16 );
mbedtls_camellia_crypt_ecb( ctx, mode, input, output );
for( i = 0; i < 16; i++ )
output[i] = (unsigned char)( output[i] ^ iv[i] );
memcpy( iv, temp, 16 );
input += 16;
output += 16;
length -= 16;
}
}
else
{
while( length > 0 )
{
for( i = 0; i < 16; i++ )
output[i] = (unsigned char)( input[i] ^ iv[i] );
mbedtls_camellia_crypt_ecb( ctx, mode, output, output );
memcpy( iv, output, 16 );
input += 16;
output += 16;
length -= 16;
}
}
return( 0 );
}
#endif /* MBEDTLS_CIPHER_MODE_CBC */
#if defined(MBEDTLS_CIPHER_MODE_CFB)
/*
* Camellia-CFB128 buffer encryption/decryption
*/
int mbedtls_camellia_crypt_cfb128( mbedtls_camellia_context *ctx,
int mode,
size_t length,
size_t *iv_off,
unsigned char iv[16],
const unsigned char *input,
unsigned char *output )
{
int c;
size_t n = *iv_off;
if( mode == MBEDTLS_CAMELLIA_DECRYPT )
{
while( length-- )
{
if( n == 0 )
mbedtls_camellia_crypt_ecb( ctx, MBEDTLS_CAMELLIA_ENCRYPT, iv, iv );
c = *input++;
*output++ = (unsigned char)( c ^ iv[n] );
iv[n] = (unsigned char) c;
n = ( n + 1 ) & 0x0F;
}
}
else
{
while( length-- )
{
if( n == 0 )
mbedtls_camellia_crypt_ecb( ctx, MBEDTLS_CAMELLIA_ENCRYPT, iv, iv );
iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ );
n = ( n + 1 ) & 0x0F;
}
}
*iv_off = n;
return( 0 );
}
#endif /* MBEDTLS_CIPHER_MODE_CFB */
#if defined(MBEDTLS_CIPHER_MODE_CTR)
/*
* Camellia-CTR buffer encryption/decryption
*/
int mbedtls_camellia_crypt_ctr( mbedtls_camellia_context *ctx,
size_t length,
size_t *nc_off,
unsigned char nonce_counter[16],
unsigned char stream_block[16],
const unsigned char *input,
unsigned char *output )
{
int c, i;
size_t n = *nc_off;
while( length-- )
{
if( n == 0 ) {
mbedtls_camellia_crypt_ecb( ctx, MBEDTLS_CAMELLIA_ENCRYPT, nonce_counter,
stream_block );
for( i = 16; i > 0; i-- )
if( ++nonce_counter[i - 1] != 0 )
break;
}
c = *input++;
*output++ = (unsigned char)( c ^ stream_block[n] );
n = ( n + 1 ) & 0x0F;
}
*nc_off = n;
return( 0 );
}
#endif /* MBEDTLS_CIPHER_MODE_CTR */
#endif /* !MBEDTLS_CAMELLIA_ALT */
#if defined(MBEDTLS_SELF_TEST)
/*
* Camellia test vectors from:
*
* http://info.isl.ntt.co.jp/crypt/eng/camellia/technology.html:
* http://info.isl.ntt.co.jp/crypt/eng/camellia/dl/cryptrec/intermediate.txt
* http://info.isl.ntt.co.jp/crypt/eng/camellia/dl/cryptrec/t_camellia.txt
* (For each bitlength: Key 0, Nr 39)
*/
#define CAMELLIA_TESTS_ECB 2
static const unsigned char camellia_test_ecb_key[3][CAMELLIA_TESTS_ECB][32] =
{
{
{ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
},
{
{ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
},
{
{ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
},
};
static const unsigned char camellia_test_ecb_plain[CAMELLIA_TESTS_ECB][16] =
{
{ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
{ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
};
static const unsigned char camellia_test_ecb_cipher[3][CAMELLIA_TESTS_ECB][16] =
{
{
{ 0x67, 0x67, 0x31, 0x38, 0x54, 0x96, 0x69, 0x73,
0x08, 0x57, 0x06, 0x56, 0x48, 0xea, 0xbe, 0x43 },
{ 0x38, 0x3C, 0x6C, 0x2A, 0xAB, 0xEF, 0x7F, 0xDE,
0x25, 0xCD, 0x47, 0x0B, 0xF7, 0x74, 0xA3, 0x31 }
},
{
{ 0xb4, 0x99, 0x34, 0x01, 0xb3, 0xe9, 0x96, 0xf8,
0x4e, 0xe5, 0xce, 0xe7, 0xd7, 0x9b, 0x09, 0xb9 },
{ 0xD1, 0x76, 0x3F, 0xC0, 0x19, 0xD7, 0x7C, 0xC9,
0x30, 0xBF, 0xF2, 0xA5, 0x6F, 0x7C, 0x93, 0x64 }
},
{
{ 0x9a, 0xcc, 0x23, 0x7d, 0xff, 0x16, 0xd7, 0x6c,
0x20, 0xef, 0x7c, 0x91, 0x9e, 0x3a, 0x75, 0x09 },
{ 0x05, 0x03, 0xFB, 0x10, 0xAB, 0x24, 0x1E, 0x7C,
0xF4, 0x5D, 0x8C, 0xDE, 0xEE, 0x47, 0x43, 0x35 }
}
};
#if defined(MBEDTLS_CIPHER_MODE_CBC)
#define CAMELLIA_TESTS_CBC 3
static const unsigned char camellia_test_cbc_key[3][32] =
{
{ 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6,
0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }
,
{ 0x8E, 0x73, 0xB0, 0xF7, 0xDA, 0x0E, 0x64, 0x52,
0xC8, 0x10, 0xF3, 0x2B, 0x80, 0x90, 0x79, 0xE5,
0x62, 0xF8, 0xEA, 0xD2, 0x52, 0x2C, 0x6B, 0x7B }
,
{ 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE,
0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81,
0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7,
0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4 }
};
static const unsigned char camellia_test_cbc_iv[16] =
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }
;
static const unsigned char camellia_test_cbc_plain[CAMELLIA_TESTS_CBC][16] =
{
{ 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96,
0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A },
{ 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C,
0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51 },
{ 0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11,
0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF }
};
static const unsigned char camellia_test_cbc_cipher[3][CAMELLIA_TESTS_CBC][16] =
{
{
{ 0x16, 0x07, 0xCF, 0x49, 0x4B, 0x36, 0xBB, 0xF0,
0x0D, 0xAE, 0xB0, 0xB5, 0x03, 0xC8, 0x31, 0xAB },
{ 0xA2, 0xF2, 0xCF, 0x67, 0x16, 0x29, 0xEF, 0x78,
0x40, 0xC5, 0xA5, 0xDF, 0xB5, 0x07, 0x48, 0x87 },
{ 0x0F, 0x06, 0x16, 0x50, 0x08, 0xCF, 0x8B, 0x8B,
0x5A, 0x63, 0x58, 0x63, 0x62, 0x54, 0x3E, 0x54 }
},
{
{ 0x2A, 0x48, 0x30, 0xAB, 0x5A, 0xC4, 0xA1, 0xA2,
0x40, 0x59, 0x55, 0xFD, 0x21, 0x95, 0xCF, 0x93 },
{ 0x5D, 0x5A, 0x86, 0x9B, 0xD1, 0x4C, 0xE5, 0x42,
0x64, 0xF8, 0x92, 0xA6, 0xDD, 0x2E, 0xC3, 0xD5 },
{ 0x37, 0xD3, 0x59, 0xC3, 0x34, 0x98, 0x36, 0xD8,
0x84, 0xE3, 0x10, 0xAD, 0xDF, 0x68, 0xC4, 0x49 }
},
{
{ 0xE6, 0xCF, 0xA3, 0x5F, 0xC0, 0x2B, 0x13, 0x4A,
0x4D, 0x2C, 0x0B, 0x67, 0x37, 0xAC, 0x3E, 0xDA },
{ 0x36, 0xCB, 0xEB, 0x73, 0xBD, 0x50, 0x4B, 0x40,
0x70, 0xB1, 0xB7, 0xDE, 0x2B, 0x21, 0xEB, 0x50 },
{ 0xE3, 0x1A, 0x60, 0x55, 0x29, 0x7D, 0x96, 0xCA,
0x33, 0x30, 0xCD, 0xF1, 0xB1, 0x86, 0x0A, 0x83 }
}
};
#endif /* MBEDTLS_CIPHER_MODE_CBC */
#if defined(MBEDTLS_CIPHER_MODE_CTR)
/*
* Camellia-CTR test vectors from:
*
* http://www.faqs.org/rfcs/rfc5528.html
*/
static const unsigned char camellia_test_ctr_key[3][16] =
{
{ 0xAE, 0x68, 0x52, 0xF8, 0x12, 0x10, 0x67, 0xCC,
0x4B, 0xF7, 0xA5, 0x76, 0x55, 0x77, 0xF3, 0x9E },
{ 0x7E, 0x24, 0x06, 0x78, 0x17, 0xFA, 0xE0, 0xD7,
0x43, 0xD6, 0xCE, 0x1F, 0x32, 0x53, 0x91, 0x63 },
{ 0x76, 0x91, 0xBE, 0x03, 0x5E, 0x50, 0x20, 0xA8,
0xAC, 0x6E, 0x61, 0x85, 0x29, 0xF9, 0xA0, 0xDC }
};
static const unsigned char camellia_test_ctr_nonce_counter[3][16] =
{
{ 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
{ 0x00, 0x6C, 0xB6, 0xDB, 0xC0, 0x54, 0x3B, 0x59,
0xDA, 0x48, 0xD9, 0x0B, 0x00, 0x00, 0x00, 0x01 },
{ 0x00, 0xE0, 0x01, 0x7B, 0x27, 0x77, 0x7F, 0x3F,
0x4A, 0x17, 0x86, 0xF0, 0x00, 0x00, 0x00, 0x01 }
};
static const unsigned char camellia_test_ctr_pt[3][48] =
{
{ 0x53, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x62,
0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x6D, 0x73, 0x67 },
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F },
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x20, 0x21, 0x22, 0x23 }
};
static const unsigned char camellia_test_ctr_ct[3][48] =
{
{ 0xD0, 0x9D, 0xC2, 0x9A, 0x82, 0x14, 0x61, 0x9A,
0x20, 0x87, 0x7C, 0x76, 0xDB, 0x1F, 0x0B, 0x3F },
{ 0xDB, 0xF3, 0xC7, 0x8D, 0xC0, 0x83, 0x96, 0xD4,
0xDA, 0x7C, 0x90, 0x77, 0x65, 0xBB, 0xCB, 0x44,
0x2B, 0x8E, 0x8E, 0x0F, 0x31, 0xF0, 0xDC, 0xA7,
0x2C, 0x74, 0x17, 0xE3, 0x53, 0x60, 0xE0, 0x48 },
{ 0xB1, 0x9D, 0x1F, 0xCD, 0xCB, 0x75, 0xEB, 0x88,
0x2F, 0x84, 0x9C, 0xE2, 0x4D, 0x85, 0xCF, 0x73,
0x9C, 0xE6, 0x4B, 0x2B, 0x5C, 0x9D, 0x73, 0xF1,
0x4F, 0x2D, 0x5D, 0x9D, 0xCE, 0x98, 0x89, 0xCD,
0xDF, 0x50, 0x86, 0x96 }
};
static const int camellia_test_ctr_len[3] =
{ 16, 32, 36 };
#endif /* MBEDTLS_CIPHER_MODE_CTR */
/*
* Checkup routine
*/
int mbedtls_camellia_self_test( int verbose )
{
int i, j, u, v;
unsigned char key[32];
unsigned char buf[64];
unsigned char src[16];
unsigned char dst[16];
#if defined(MBEDTLS_CIPHER_MODE_CBC)
unsigned char iv[16];
#endif
#if defined(MBEDTLS_CIPHER_MODE_CTR)
size_t offset, len;
unsigned char nonce_counter[16];
unsigned char stream_block[16];
#endif
mbedtls_camellia_context ctx;
memset( key, 0, 32 );
for( j = 0; j < 6; j++ ) {
u = j >> 1;
v = j & 1;
if( verbose != 0 )
mbedtls_printf( " CAMELLIA-ECB-%3d (%s): ", 128 + u * 64,
(v == MBEDTLS_CAMELLIA_DECRYPT) ? "dec" : "enc");
for( i = 0; i < CAMELLIA_TESTS_ECB; i++ ) {
memcpy( key, camellia_test_ecb_key[u][i], 16 + 8 * u );
if( v == MBEDTLS_CAMELLIA_DECRYPT ) {
mbedtls_camellia_setkey_dec( &ctx, key, 128 + u * 64 );
memcpy( src, camellia_test_ecb_cipher[u][i], 16 );
memcpy( dst, camellia_test_ecb_plain[i], 16 );
} else { /* MBEDTLS_CAMELLIA_ENCRYPT */
mbedtls_camellia_setkey_enc( &ctx, key, 128 + u * 64 );
memcpy( src, camellia_test_ecb_plain[i], 16 );
memcpy( dst, camellia_test_ecb_cipher[u][i], 16 );
}
mbedtls_camellia_crypt_ecb( &ctx, v, src, buf );
if( memcmp( buf, dst, 16 ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
return( 1 );
}
}
if( verbose != 0 )
mbedtls_printf( "passed\n" );
}
if( verbose != 0 )
mbedtls_printf( "\n" );
#if defined(MBEDTLS_CIPHER_MODE_CBC)
/*
* CBC mode
*/
for( j = 0; j < 6; j++ )
{
u = j >> 1;
v = j & 1;
if( verbose != 0 )
mbedtls_printf( " CAMELLIA-CBC-%3d (%s): ", 128 + u * 64,
( v == MBEDTLS_CAMELLIA_DECRYPT ) ? "dec" : "enc" );
memcpy( src, camellia_test_cbc_iv, 16 );
memcpy( dst, camellia_test_cbc_iv, 16 );
memcpy( key, camellia_test_cbc_key[u], 16 + 8 * u );
if( v == MBEDTLS_CAMELLIA_DECRYPT ) {
mbedtls_camellia_setkey_dec( &ctx, key, 128 + u * 64 );
} else {
mbedtls_camellia_setkey_enc( &ctx, key, 128 + u * 64 );
}
for( i = 0; i < CAMELLIA_TESTS_CBC; i++ ) {
if( v == MBEDTLS_CAMELLIA_DECRYPT ) {
memcpy( iv , src, 16 );
memcpy( src, camellia_test_cbc_cipher[u][i], 16 );
memcpy( dst, camellia_test_cbc_plain[i], 16 );
} else { /* MBEDTLS_CAMELLIA_ENCRYPT */
memcpy( iv , dst, 16 );
memcpy( src, camellia_test_cbc_plain[i], 16 );
memcpy( dst, camellia_test_cbc_cipher[u][i], 16 );
}
mbedtls_camellia_crypt_cbc( &ctx, v, 16, iv, src, buf );
if( memcmp( buf, dst, 16 ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
return( 1 );
}
}
if( verbose != 0 )
mbedtls_printf( "passed\n" );
}
#endif /* MBEDTLS_CIPHER_MODE_CBC */
if( verbose != 0 )
mbedtls_printf( "\n" );
#if defined(MBEDTLS_CIPHER_MODE_CTR)
/*
* CTR mode
*/
for( i = 0; i < 6; i++ )
{
u = i >> 1;
v = i & 1;
if( verbose != 0 )
mbedtls_printf( " CAMELLIA-CTR-128 (%s): ",
( v == MBEDTLS_CAMELLIA_DECRYPT ) ? "dec" : "enc" );
memcpy( nonce_counter, camellia_test_ctr_nonce_counter[u], 16 );
memcpy( key, camellia_test_ctr_key[u], 16 );
offset = 0;
mbedtls_camellia_setkey_enc( &ctx, key, 128 );
if( v == MBEDTLS_CAMELLIA_DECRYPT )
{
len = camellia_test_ctr_len[u];
memcpy( buf, camellia_test_ctr_ct[u], len );
mbedtls_camellia_crypt_ctr( &ctx, len, &offset, nonce_counter, stream_block,
buf, buf );
if( memcmp( buf, camellia_test_ctr_pt[u], len ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
return( 1 );
}
}
else
{
len = camellia_test_ctr_len[u];
memcpy( buf, camellia_test_ctr_pt[u], len );
mbedtls_camellia_crypt_ctr( &ctx, len, &offset, nonce_counter, stream_block,
buf, buf );
if( memcmp( buf, camellia_test_ctr_ct[u], len ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
return( 1 );
}
}
if( verbose != 0 )
mbedtls_printf( "passed\n" );
}
if( verbose != 0 )
mbedtls_printf( "\n" );
#endif /* MBEDTLS_CIPHER_MODE_CTR */
return( 0 );
}
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_CAMELLIA_C */
/*
* NIST SP800-38C compliant CCM implementation
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed 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.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* Definition of CCM:
* http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf
* RFC 3610 "Counter with CBC-MAC (CCM)"
*
* Related:
* RFC 5116 "An Interface and Algorithms for Authenticated Encryption"
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_CCM_C)
#include "mbedtls/ccm.h"
#include <string.h>
#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n ) {
volatile unsigned char *p = v; while( n-- ) *p++ = 0;
}
#define CCM_ENCRYPT 0
#define CCM_DECRYPT 1
/*
* Initialize context
*/
void mbedtls_ccm_init( mbedtls_ccm_context *ctx )
{
memset( ctx, 0, sizeof( mbedtls_ccm_context ) );
}
int mbedtls_ccm_setkey( mbedtls_ccm_context *ctx,
mbedtls_cipher_id_t cipher,
const unsigned char *key,
unsigned int keybits )
{
int ret;
const mbedtls_cipher_info_t *cipher_info;
cipher_info = mbedtls_cipher_info_from_values( cipher, keybits, MBEDTLS_MODE_ECB );
if( cipher_info == NULL )
return( MBEDTLS_ERR_CCM_BAD_INPUT );
if( cipher_info->block_size != 16 )
return( MBEDTLS_ERR_CCM_BAD_INPUT );
mbedtls_cipher_free( &ctx->cipher_ctx );
if( ( ret = mbedtls_cipher_setup( &ctx->cipher_ctx, cipher_info ) ) != 0 )
return( ret );
if( ( ret = mbedtls_cipher_setkey( &ctx->cipher_ctx, key, keybits,
MBEDTLS_ENCRYPT ) ) != 0 )
{
return( ret );
}
return( 0 );
}
/*
* Free context
*/
void mbedtls_ccm_free( mbedtls_ccm_context *ctx )
{
mbedtls_cipher_free( &ctx->cipher_ctx );
mbedtls_zeroize( ctx, sizeof( mbedtls_ccm_context ) );
}
/*
* Macros for common operations.
* Results in smaller compiled code than static inline functions.
*/
/*
* Update the CBC-MAC state in y using a block in b
* (Always using b as the source helps the compiler optimise a bit better.)
*/
#define UPDATE_CBC_MAC \
for( i = 0; i < 16; i++ ) \
y[i] ^= b[i]; \
\
if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, y, 16, y, &olen ) ) != 0 ) \
return( ret );
/*
* Encrypt or decrypt a partial block with CTR
* Warning: using b for temporary storage! src and dst must not be b!
* This avoids allocating one more 16 bytes buffer while allowing src == dst.
*/
#define CTR_CRYPT( dst, src, len ) \
if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctr, 16, b, &olen ) ) != 0 ) \
return( ret ); \
\
for( i = 0; i < len; i++ ) \
dst[i] = src[i] ^ b[i];
/*
* Authenticated encryption or decryption
*/
static int ccm_auth_crypt( mbedtls_ccm_context *ctx, int mode, size_t length,
const unsigned char *iv, size_t iv_len,
const unsigned char *add, size_t add_len,
const unsigned char *input, unsigned char *output,
unsigned char *tag, size_t tag_len )
{
int ret;
unsigned char i;
unsigned char q;
size_t len_left, olen;
unsigned char b[16];
unsigned char y[16];
unsigned char ctr[16];
const unsigned char *src;
unsigned char *dst;
/*
* Check length requirements: SP800-38C A.1
* Additional requirement: a < 2^16 - 2^8 to simplify the code.
* 'length' checked later (when writing it to the first block)
*/
if( tag_len < 4 || tag_len > 16 || tag_len % 2 != 0 )
return( MBEDTLS_ERR_CCM_BAD_INPUT );
/* Also implies q is within bounds */
if( iv_len < 7 || iv_len > 13 )
return( MBEDTLS_ERR_CCM_BAD_INPUT );
if( add_len > 0xFF00 )
return( MBEDTLS_ERR_CCM_BAD_INPUT );
q = 16 - 1 - (unsigned char) iv_len;
/*
* First block B_0:
* 0 .. 0 flags
* 1 .. iv_len nonce (aka iv)
* iv_len+1 .. 15 length
*
* With flags as (bits):
* 7 0
* 6 add present?
* 5 .. 3 (t - 2) / 2
* 2 .. 0 q - 1
*/
b[0] = 0;
b[0] |= ( add_len > 0 ) << 6;
b[0] |= ( ( tag_len - 2 ) / 2 ) << 3;
b[0] |= q - 1;
memcpy( b + 1, iv, iv_len );
for( i = 0, len_left = length; i < q; i++, len_left >>= 8 )
b[15-i] = (unsigned char)( len_left & 0xFF );
if( len_left > 0 )
return( MBEDTLS_ERR_CCM_BAD_INPUT );
/* Start CBC-MAC with first block */
memset( y, 0, 16 );
UPDATE_CBC_MAC;
/*
* If there is additional data, update CBC-MAC with
* add_len, add, 0 (padding to a block boundary)
*/
if( add_len > 0 )
{
size_t use_len;
len_left = add_len;
src = add;
memset( b, 0, 16 );
b[0] = (unsigned char)( ( add_len >> 8 ) & 0xFF );
b[1] = (unsigned char)( ( add_len ) & 0xFF );
use_len = len_left < 16 - 2 ? len_left : 16 - 2;
memcpy( b + 2, src, use_len );
len_left -= use_len;
src += use_len;
UPDATE_CBC_MAC;
while( len_left > 0 )
{
use_len = len_left > 16 ? 16 : len_left;
memset( b, 0, 16 );
memcpy( b, src, use_len );
UPDATE_CBC_MAC;
len_left -= use_len;
src += use_len;
}
}
/*
* Prepare counter block for encryption:
* 0 .. 0 flags
* 1 .. iv_len nonce (aka iv)
* iv_len+1 .. 15 counter (initially 1)
*
* With flags as (bits):
* 7 .. 3 0
* 2 .. 0 q - 1
*/
ctr[0] = q - 1;
memcpy( ctr + 1, iv, iv_len );
memset( ctr + 1 + iv_len, 0, q );
ctr[15] = 1;
/*
* Authenticate and {en,de}crypt the message.
*
* The only difference between encryption and decryption is
* the respective order of authentication and {en,de}cryption.
*/
len_left = length;
src = input;
dst = output;
while( len_left > 0 )
{
size_t use_len = len_left > 16 ? 16 : len_left;
if( mode == CCM_ENCRYPT )
{
memset( b, 0, 16 );
memcpy( b, src, use_len );
UPDATE_CBC_MAC;
}
CTR_CRYPT( dst, src, use_len );
if( mode == CCM_DECRYPT )
{
memset( b, 0, 16 );
memcpy( b, dst, use_len );
UPDATE_CBC_MAC;
}
dst += use_len;
src += use_len;
len_left -= use_len;
/*
* Increment counter.
* No need to check for overflow thanks to the length check above.
*/
for( i = 0; i < q; i++ )
if( ++ctr[15-i] != 0 )
break;
}
/*
* Authentication: reset counter and crypt/mask internal tag
*/
for( i = 0; i < q; i++ )
ctr[15-i] = 0;
CTR_CRYPT( y, y, 16 );
memcpy( tag, y, tag_len );
return( 0 );
}
/*
* Authenticated encryption
*/
int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length,
const unsigned char *iv, size_t iv_len,
const unsigned char *add, size_t add_len,
const unsigned char *input, unsigned char *output,
unsigned char *tag, size_t tag_len )
{
return( ccm_auth_crypt( ctx, CCM_ENCRYPT, length, iv, iv_len,
add, add_len, input, output, tag, tag_len ) );
}
/*
* Authenticated decryption
*/
int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length,
const unsigned char *iv, size_t iv_len,
const unsigned char *add, size_t add_len,
const unsigned char *input, unsigned char *output,
const unsigned char *tag, size_t tag_len )
{
int ret;
unsigned char check_tag[16];
unsigned char i;
int diff;
if( ( ret = ccm_auth_crypt( ctx, CCM_DECRYPT, length,
iv, iv_len, add, add_len,
input, output, check_tag, tag_len ) ) != 0 )
{
return( ret );
}
/* Check tag in "constant-time" */
for( diff = 0, i = 0; i < tag_len; i++ )
diff |= tag[i] ^ check_tag[i];
if( diff != 0 )
{
mbedtls_zeroize( output, length );
return( MBEDTLS_ERR_CCM_AUTH_FAILED );
}
return( 0 );
}
#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
/*
* Examples 1 to 3 from SP800-38C Appendix C
*/
#define NB_TESTS 3
/*
* The data is the same for all tests, only the used length changes
*/
static const unsigned char key[] = {
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
};
static const unsigned char iv[] = {
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b
};
static const unsigned char ad[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13
};
static const unsigned char msg[] = {
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
};
static const size_t iv_len [NB_TESTS] = { 7, 8, 12 };
static const size_t add_len[NB_TESTS] = { 8, 16, 20 };
static const size_t msg_len[NB_TESTS] = { 4, 16, 24 };
static const size_t tag_len[NB_TESTS] = { 4, 6, 8 };
static const unsigned char res[NB_TESTS][32] = {
{ 0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d },
{ 0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62,
0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d,
0x1f, 0xc6, 0x4f, 0xbf, 0xac, 0xcd },
{ 0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a,
0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b,
0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5,
0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51 }
};
int mbedtls_ccm_self_test( int verbose )
{
mbedtls_ccm_context ctx;
unsigned char out[32];
size_t i;
int ret;
mbedtls_ccm_init( &ctx );
if( mbedtls_ccm_setkey( &ctx, MBEDTLS_CIPHER_ID_AES, key, 8 * sizeof key ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( " CCM: setup failed" );
return( 1 );
}
for( i = 0; i < NB_TESTS; i++ )
{
if( verbose != 0 )
mbedtls_printf( " CCM-AES #%u: ", (unsigned int) i + 1 );
ret = mbedtls_ccm_encrypt_and_tag( &ctx, msg_len[i],
iv, iv_len[i], ad, add_len[i],
msg, out,
out + msg_len[i], tag_len[i] );
if( ret != 0 ||
memcmp( out, res[i], msg_len[i] + tag_len[i] ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
return( 1 );
}
ret = mbedtls_ccm_auth_decrypt( &ctx, msg_len[i],
iv, iv_len[i], ad, add_len[i],
res[i], out,
res[i] + msg_len[i], tag_len[i] );
if( ret != 0 ||
memcmp( out, msg, msg_len[i] ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
return( 1 );
}
if( verbose != 0 )
mbedtls_printf( "passed\n" );
}
mbedtls_ccm_free( &ctx );
if( verbose != 0 )
mbedtls_printf( "\n" );
return( 0 );
}
#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
#endif /* MBEDTLS_CCM_C */
/*
* X.509 test certificates
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed 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.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#include "mbedtls/certs.h"
#if defined(MBEDTLS_SELF_TEST)
#if defined(MBEDTLS_CERTS_C)
#if defined(MBEDTLS_ECDSA_C)
#define TEST_CA_CRT_EC \
"-----BEGIN CERTIFICATE-----\r\n" \
"MIICUjCCAdegAwIBAgIJAMFD4n5iQ8zoMAoGCCqGSM49BAMCMD4xCzAJBgNVBAYT\r\n" \
"Ak5MMREwDwYDVQQKEwhQb2xhclNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBF\r\n" \
"QyBDQTAeFw0xMzA5MjQxNTQ5NDhaFw0yMzA5MjIxNTQ5NDhaMD4xCzAJBgNVBAYT\r\n" \
"Ak5MMREwDwYDVQQKEwhQb2xhclNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBF\r\n" \
"QyBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IABMPaKzRBN1gvh1b+/Im6KUNLTuBu\r\n" \
"ww5XUzM5WNRStJGVOQsj318XJGJI/BqVKc4sLYfCiFKAr9ZqqyHduNMcbli4yuiy\r\n" \
"aY7zQa0pw7RfdadHb9UZKVVpmlM7ILRmFmAzHqOBoDCBnTAdBgNVHQ4EFgQUnW0g\r\n" \
"JEkBPyvLeLUZvH4kydv7NnwwbgYDVR0jBGcwZYAUnW0gJEkBPyvLeLUZvH4kydv7\r\n" \
"NnyhQqRAMD4xCzAJBgNVBAYTAk5MMREwDwYDVQQKEwhQb2xhclNTTDEcMBoGA1UE\r\n" \
"AxMTUG9sYXJzc2wgVGVzdCBFQyBDQYIJAMFD4n5iQ8zoMAwGA1UdEwQFMAMBAf8w\r\n" \
"CgYIKoZIzj0EAwIDaQAwZgIxAMO0YnNWKJUAfXgSJtJxexn4ipg+kv4znuR50v56\r\n" \
"t4d0PCu412mUC6Nnd7izvtE2MgIxAP1nnJQjZ8BWukszFQDG48wxCCyci9qpdSMv\r\n" \
"uCjn8pwUOkABXK8Mss90fzCfCEOtIA==\r\n" \
"-----END CERTIFICATE-----\r\n"
const char mbedtls_test_ca_crt_ec[] = TEST_CA_CRT_EC;
const char mbedtls_test_ca_key_ec[] =
"-----BEGIN EC PRIVATE KEY-----\r\n"
"Proc-Type: 4,ENCRYPTED\r\n"
"DEK-Info: DES-EDE3-CBC,307EAB469933D64E\r\n"
"\r\n"
"IxbrRmKcAzctJqPdTQLA4SWyBYYGYJVkYEna+F7Pa5t5Yg/gKADrFKcm6B72e7DG\r\n"
"ihExtZI648s0zdYw6qSJ74vrPSuWDe5qm93BqsfVH9svtCzWHW0pm1p0KTBCFfUq\r\n"
"UsuWTITwJImcnlAs1gaRZ3sAWm7cOUidL0fo2G0fYUFNcYoCSLffCFTEHBuPnagb\r\n"
"a77x/sY1Bvii8S9/XhDTb6pTMx06wzrm\r\n"
"-----END EC PRIVATE KEY-----\r\n";
const char mbedtls_test_ca_pwd_ec[] = "PolarSSLTest";
const char mbedtls_test_srv_crt_ec[] =
"-----BEGIN CERTIFICATE-----\r\n"
"MIICHzCCAaWgAwIBAgIBCTAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJOTDERMA8G\r\n"
"A1UEChMIUG9sYXJTU0wxHDAaBgNVBAMTE1BvbGFyc3NsIFRlc3QgRUMgQ0EwHhcN\r\n"
"MTMwOTI0MTU1MjA0WhcNMjMwOTIyMTU1MjA0WjA0MQswCQYDVQQGEwJOTDERMA8G\r\n"
"A1UEChMIUG9sYXJTU0wxEjAQBgNVBAMTCWxvY2FsaG9zdDBZMBMGByqGSM49AgEG\r\n"
"CCqGSM49AwEHA0IABDfMVtl2CR5acj7HWS3/IG7ufPkGkXTQrRS192giWWKSTuUA\r\n"
"2CMR/+ov0jRdXRa9iojCa3cNVc2KKg76Aci07f+jgZ0wgZowCQYDVR0TBAIwADAd\r\n"
"BgNVHQ4EFgQUUGGlj9QH2deCAQzlZX+MY0anE74wbgYDVR0jBGcwZYAUnW0gJEkB\r\n"
"PyvLeLUZvH4kydv7NnyhQqRAMD4xCzAJBgNVBAYTAk5MMREwDwYDVQQKEwhQb2xh\r\n"
"clNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBFQyBDQYIJAMFD4n5iQ8zoMAoG\r\n"
"CCqGSM49BAMCA2gAMGUCMQCaLFzXptui5WQN8LlO3ddh1hMxx6tzgLvT03MTVK2S\r\n"
"C12r0Lz3ri/moSEpNZWqPjkCMCE2f53GXcYLqyfyJR078c/xNSUU5+Xxl7VZ414V\r\n"
"fGa5kHvHARBPc8YAIVIqDvHH1Q==\r\n"
"-----END CERTIFICATE-----\r\n";
const char mbedtls_test_srv_key_ec[] =
"-----BEGIN EC PRIVATE KEY-----\r\n"
"MHcCAQEEIPEqEyB2AnCoPL/9U/YDHvdqXYbIogTywwyp6/UfDw6noAoGCCqGSM49\r\n"
"AwEHoUQDQgAEN8xW2XYJHlpyPsdZLf8gbu58+QaRdNCtFLX3aCJZYpJO5QDYIxH/\r\n"
"6i/SNF1dFr2KiMJrdw1VzYoqDvoByLTt/w==\r\n"
"-----END EC PRIVATE KEY-----\r\n";
const char mbedtls_test_cli_crt_ec[] =
"-----BEGIN CERTIFICATE-----\r\n"
"MIICLDCCAbKgAwIBAgIBDTAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJOTDERMA8G\r\n"
"A1UEChMIUG9sYXJTU0wxHDAaBgNVBAMTE1BvbGFyc3NsIFRlc3QgRUMgQ0EwHhcN\r\n"
"MTMwOTI0MTU1MjA0WhcNMjMwOTIyMTU1MjA0WjBBMQswCQYDVQQGEwJOTDERMA8G\r\n"
"A1UEChMIUG9sYXJTU0wxHzAdBgNVBAMTFlBvbGFyU1NMIFRlc3QgQ2xpZW50IDIw\r\n"
"WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARX5a6xc9/TrLuTuIH/Eq7u5lOszlVT\r\n"
"9jQOzC7jYyUL35ji81xgNpbA1RgUcOV/n9VLRRjlsGzVXPiWj4dwo+THo4GdMIGa\r\n"
"MAkGA1UdEwQCMAAwHQYDVR0OBBYEFHoAX4Zk/OBd5REQO7LmO8QmP8/iMG4GA1Ud\r\n"
"IwRnMGWAFJ1tICRJAT8ry3i1Gbx+JMnb+zZ8oUKkQDA+MQswCQYDVQQGEwJOTDER\r\n"
"MA8GA1UEChMIUG9sYXJTU0wxHDAaBgNVBAMTE1BvbGFyc3NsIFRlc3QgRUMgQ0GC\r\n"
"CQDBQ+J+YkPM6DAKBggqhkjOPQQDAgNoADBlAjBKZQ17IIOimbmoD/yN7o89u3BM\r\n"
"lgOsjnhw3fIOoLIWy2WOGsk/LGF++DzvrRzuNiACMQCd8iem1XS4JK7haj8xocpU\r\n"
"LwjQje5PDGHfd3h9tP38Qknu5bJqws0md2KOKHyeV0U=\r\n"
"-----END CERTIFICATE-----\r\n";
const char mbedtls_test_cli_key_ec[] =
"-----BEGIN EC PRIVATE KEY-----\r\n"
"MHcCAQEEIPb3hmTxZ3/mZI3vyk7p3U3wBf+WIop6hDhkFzJhmLcqoAoGCCqGSM49\r\n"
"AwEHoUQDQgAEV+WusXPf06y7k7iB/xKu7uZTrM5VU/Y0Dswu42MlC9+Y4vNcYDaW\r\n"
"wNUYFHDlf5/VS0UY5bBs1Vz4lo+HcKPkxw==\r\n"
"-----END EC PRIVATE KEY-----\r\n";
const size_t mbedtls_test_ca_crt_ec_len = sizeof( mbedtls_test_ca_crt_ec );
const size_t mbedtls_test_ca_key_ec_len = sizeof( mbedtls_test_ca_key_ec );
const size_t mbedtls_test_ca_pwd_ec_len = sizeof( mbedtls_test_ca_pwd_ec ) - 1;
const size_t mbedtls_test_srv_crt_ec_len = sizeof( mbedtls_test_srv_crt_ec );
const size_t mbedtls_test_srv_key_ec_len = sizeof( mbedtls_test_srv_key_ec );
const size_t mbedtls_test_cli_crt_ec_len = sizeof( mbedtls_test_cli_crt_ec );
const size_t mbedtls_test_cli_key_ec_len = sizeof( mbedtls_test_cli_key_ec );
#else
#define TEST_CA_CRT_EC
#endif /* MBEDTLS_ECDSA_C */
#if defined(MBEDTLS_RSA_C)
#define TEST_CA_CRT_RSA \
"-----BEGIN CERTIFICATE-----\r\n" \
"MIIDhzCCAm+gAwIBAgIBADANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER\r\n" \
"MA8GA1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n" \
"MTEwMjEyMTQ0NDAwWhcNMjEwMjEyMTQ0NDAwWjA7MQswCQYDVQQGEwJOTDERMA8G\r\n" \
"A1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwggEiMA0G\r\n" \
"CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDA3zf8F7vglp0/ht6WMn1EpRagzSHx\r\n" \
"mdTs6st8GFgIlKXsm8WL3xoemTiZhx57wI053zhdcHgH057Zk+i5clHFzqMwUqny\r\n" \
"50BwFMtEonILwuVA+T7lpg6z+exKY8C4KQB0nFc7qKUEkHHxvYPZP9al4jwqj+8n\r\n" \
"YMPGn8u67GB9t+aEMr5P+1gmIgNb1LTV+/Xjli5wwOQuvfwu7uJBVcA0Ln0kcmnL\r\n" \
"R7EUQIN9Z/SG9jGr8XmksrUuEvmEF/Bibyc+E1ixVA0hmnM3oTDPb5Lc9un8rNsu\r\n" \
"KNF+AksjoBXyOGVkCeoMbo4bF6BxyLObyavpw/LPh5aPgAIynplYb6LVAgMBAAGj\r\n" \
"gZUwgZIwDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQUtFrkpbPe0lL2udWmlQ/rPrzH\r\n" \
"/f8wYwYDVR0jBFwwWoAUtFrkpbPe0lL2udWmlQ/rPrzH/f+hP6Q9MDsxCzAJBgNV\r\n" \
"BAYTAk5MMREwDwYDVQQKEwhQb2xhclNTTDEZMBcGA1UEAxMQUG9sYXJTU0wgVGVz\r\n" \
"dCBDQYIBADANBgkqhkiG9w0BAQUFAAOCAQEAuP1U2ABUkIslsCfdlc2i94QHHYeJ\r\n" \
"SsR4EdgHtdciUI5I62J6Mom+Y0dT/7a+8S6MVMCZP6C5NyNyXw1GWY/YR82XTJ8H\r\n" \
"DBJiCTok5DbZ6SzaONBzdWHXwWwmi5vg1dxn7YxrM9d0IjxM27WNKs4sDQhZBQkF\r\n" \
"pjmfs2cb4oPl4Y9T9meTx/lvdkRYEug61Jfn6cA+qHpyPYdTH+UshITnmp5/Ztkf\r\n" \
"m/UTSLBNFNHesiTZeH31NcxYGdHSme9Nc/gfidRa0FLOCfWxRlFqAI47zG9jAQCZ\r\n" \
"7Z2mCGDNMhjQc+BYcdnl0lPXjdDK6V0qCg1dVewhUBcW5gZKzV7e9+DpVA==\r\n" \
"-----END CERTIFICATE-----\r\n"
const char mbedtls_test_ca_crt_rsa[] = TEST_CA_CRT_RSA;
const char mbedtls_test_ca_key_rsa[] =
"-----BEGIN RSA PRIVATE KEY-----\r\n"
"Proc-Type: 4,ENCRYPTED\r\n"
"DEK-Info: DES-EDE3-CBC,A8A95B05D5B7206B\r\n"
"\r\n"
"9Qd9GeArejl1GDVh2lLV1bHt0cPtfbh5h/5zVpAVaFpqtSPMrElp50Rntn9et+JA\r\n"
"7VOyboR+Iy2t/HU4WvA687k3Bppe9GwKHjHhtl//8xFKwZr3Xb5yO5JUP8AUctQq\r\n"
"Nb8CLlZyuUC+52REAAthdWgsX+7dJO4yabzUcQ22Tp9JSD0hiL43BlkWYUNK3dAo\r\n"
"PZlmiptjnzVTjg1MxsBSydZinWOLBV8/JQgxSPo2yD4uEfig28qbvQ2wNIn0pnAb\r\n"
"GxnSAOazkongEGfvcjIIs+LZN9gXFhxcOh6kc4Q/c99B7QWETwLLkYgZ+z1a9VY9\r\n"
"gEU7CwCxYCD+h9hY6FPmsK0/lC4O7aeRKpYq00rPPxs6i7phiexg6ax6yTMmArQq\r\n"
"QmK3TAsJm8V/J5AWpLEV6jAFgRGymGGHnof0DXzVWZidrcZJWTNuGEX90nB3ee2w\r\n"
"PXJEFWKoD3K3aFcSLdHYr3mLGxP7H9ThQai9VsycxZKS5kwvBKQ//YMrmFfwPk8x\r\n"
"vTeY4KZMaUrveEel5tWZC94RSMKgxR6cyE1nBXyTQnDOGbfpNNgBKxyKbINWoOJU\r\n"
"WJZAwlsQn+QzCDwpri7+sV1mS3gBE6UY7aQmnmiiaC2V3Hbphxct/en5QsfDOt1X\r\n"
"JczSfpRWLlbPznZg8OQh/VgCMA58N5DjOzTIK7sJJ5r+94ZBTCpgAMbF588f0NTR\r\n"
"KCe4yrxGJR7X02M4nvD4IwOlpsQ8xQxZtOSgXv4LkxvdU9XJJKWZ/XNKJeWztxSe\r\n"
"Z1vdTc2YfsDBA2SEv33vxHx2g1vqtw8SjDRT2RaQSS0QuSaMJimdOX6mTOCBKk1J\r\n"
"9Q5mXTrER+/LnK0jEmXsBXWA5bqqVZIyahXSx4VYZ7l7w/PHiUDtDgyRhMMKi4n2\r\n"
"iQvQcWSQTjrpnlJbca1/DkpRt3YwrvJwdqb8asZU2VrNETh5x0QVefDRLFiVpif/\r\n"
"tUaeAe/P1F8OkS7OIZDs1SUbv/sD2vMbhNkUoCms3/PvNtdnvgL4F0zhaDpKCmlT\r\n"
"P8vx49E7v5CyRNmED9zZg4o3wmMqrQO93PtTug3Eu9oVx1zPQM1NVMyBa2+f29DL\r\n"
"1nuTCeXdo9+ni45xx+jAI4DCwrRdhJ9uzZyC6962H37H6D+5naNvClFR1s6li1Gb\r\n"
"nqPoiy/OBsEx9CaDGcqQBp5Wme/3XW+6z1ISOx+igwNTVCT14mHdBMbya0eIKft5\r\n"
"X+GnwtgEMyCYyyWuUct8g4RzErcY9+yW9Om5Hzpx4zOuW4NPZgPDTgK+t2RSL/Yq\r\n"
"rE1njrgeGYcVeG3f+OftH4s6fPbq7t1A5ZgUscbLMBqr9tK+OqygR4EgKBPsH6Cz\r\n"
"L6zlv/2RV0qAHvVuDJcIDIgwY5rJtINEm32rhOeFNJwZS5MNIC1czXZx5//ugX7l\r\n"
"I4sy5nbVhwSjtAk8Xg5dZbdTZ6mIrb7xqH+fdakZor1khG7bC2uIwibD3cSl2XkR\r\n"
"wN48lslbHnqqagr6Xm1nNOSVl8C/6kbJEsMpLhAezfRtGwvOucoaE+WbeUNolGde\r\n"
"P/eQiddSf0brnpiLJRh7qZrl9XuqYdpUqnoEdMAfotDOID8OtV7gt8a48ad8VPW2\r\n"
"-----END RSA PRIVATE KEY-----\r\n";
const char mbedtls_test_ca_pwd_rsa[] = "PolarSSLTest";
const char mbedtls_test_srv_crt_rsa[] =
"-----BEGIN CERTIFICATE-----\r\n"
"MIIDNzCCAh+gAwIBAgIBAjANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER\r\n"
"MA8GA1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n"
"MTEwMjEyMTQ0NDA2WhcNMjEwMjEyMTQ0NDA2WjA0MQswCQYDVQQGEwJOTDERMA8G\r\n"
"A1UEChMIUG9sYXJTU0wxEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcN\r\n"
"AQEBBQADggEPADCCAQoCggEBAMFNo93nzR3RBNdJcriZrA545Do8Ss86ExbQWuTN\r\n"
"owCIp+4ea5anUrSQ7y1yej4kmvy2NKwk9XfgJmSMnLAofaHa6ozmyRyWvP7BBFKz\r\n"
"NtSj+uGxdtiQwWG0ZlI2oiZTqqt0Xgd9GYLbKtgfoNkNHC1JZvdbJXNG6AuKT2kM\r\n"
"tQCQ4dqCEGZ9rlQri2V5kaHiYcPNQEkI7mgM8YuG0ka/0LiqEQMef1aoGh5EGA8P\r\n"
"hYvai0Re4hjGYi/HZo36Xdh98yeJKQHFkA4/J/EwyEoO79bex8cna8cFPXrEAjya\r\n"
"HT4P6DSYW8tzS1KW2BGiLICIaTla0w+w3lkvEcf36hIBMJcCAwEAAaNNMEswCQYD\r\n"
"VR0TBAIwADAdBgNVHQ4EFgQUpQXoZLjc32APUBJNYKhkr02LQ5MwHwYDVR0jBBgw\r\n"
"FoAUtFrkpbPe0lL2udWmlQ/rPrzH/f8wDQYJKoZIhvcNAQEFBQADggEBAJxnXClY\r\n"
"oHkbp70cqBrsGXLybA74czbO5RdLEgFs7rHVS9r+c293luS/KdliLScZqAzYVylw\r\n"
"UfRWvKMoWhHYKp3dEIS4xTXk6/5zXxhv9Rw8SGc8qn6vITHk1S1mPevtekgasY5Y\r\n"
"iWQuM3h4YVlRH3HHEMAD1TnAexfXHHDFQGe+Bd1iAbz1/sH9H8l4StwX6egvTK3M\r\n"
"wXRwkKkvjKaEDA9ATbZx0mI8LGsxSuCqe9r9dyjmttd47J1p1Rulz3CLzaRcVIuS\r\n"
"RRQfaD8neM9c1S/iJ/amTVqJxA1KOdOS5780WhPfSArA+g4qAmSjelc3p4wWpha8\r\n"
"zhuYwjVuX6JHG0c=\r\n"
"-----END CERTIFICATE-----\r\n";
const char mbedtls_test_srv_key_rsa[] =
"-----BEGIN RSA PRIVATE KEY-----\r\n"
"MIIEpAIBAAKCAQEAwU2j3efNHdEE10lyuJmsDnjkOjxKzzoTFtBa5M2jAIin7h5r\r\n"
"lqdStJDvLXJ6PiSa/LY0rCT1d+AmZIycsCh9odrqjObJHJa8/sEEUrM21KP64bF2\r\n"
"2JDBYbRmUjaiJlOqq3ReB30Zgtsq2B+g2Q0cLUlm91slc0boC4pPaQy1AJDh2oIQ\r\n"
"Zn2uVCuLZXmRoeJhw81ASQjuaAzxi4bSRr/QuKoRAx5/VqgaHkQYDw+Fi9qLRF7i\r\n"
"GMZiL8dmjfpd2H3zJ4kpAcWQDj8n8TDISg7v1t7HxydrxwU9esQCPJodPg/oNJhb\r\n"
"y3NLUpbYEaIsgIhpOVrTD7DeWS8Rx/fqEgEwlwIDAQABAoIBAQCXR0S8EIHFGORZ\r\n"
"++AtOg6eENxD+xVs0f1IeGz57Tjo3QnXX7VBZNdj+p1ECvhCE/G7XnkgU5hLZX+G\r\n"
"Z0jkz/tqJOI0vRSdLBbipHnWouyBQ4e/A1yIJdlBtqXxJ1KE/ituHRbNc4j4kL8Z\r\n"
"/r6pvwnTI0PSx2Eqs048YdS92LT6qAv4flbNDxMn2uY7s4ycS4Q8w1JXnCeaAnYm\r\n"
"WYI5wxO+bvRELR2Mcz5DmVnL8jRyml6l6582bSv5oufReFIbyPZbQWlXgYnpu6He\r\n"
"GTc7E1zKYQGG/9+DQUl/1vQuCPqQwny0tQoX2w5tdYpdMdVm+zkLtbajzdTviJJa\r\n"
"TWzL6lt5AoGBAN86+SVeJDcmQJcv4Eq6UhtRr4QGMiQMz0Sod6ettYxYzMgxtw28\r\n"
"CIrgpozCc+UaZJLo7UxvC6an85r1b2nKPCLQFaggJ0H4Q0J/sZOhBIXaoBzWxveK\r\n"
"nupceKdVxGsFi8CDy86DBfiyFivfBj+47BbaQzPBj7C4rK7UlLjab2rDAoGBAN2u\r\n"
"AM2gchoFiu4v1HFL8D7lweEpi6ZnMJjnEu/dEgGQJFjwdpLnPbsj4c75odQ4Gz8g\r\n"
"sw9lao9VVzbusoRE/JGI4aTdO0pATXyG7eG1Qu+5Yc1YGXcCrliA2xM9xx+d7f+s\r\n"
"mPzN+WIEg5GJDYZDjAzHG5BNvi/FfM1C9dOtjv2dAoGAF0t5KmwbjWHBhcVqO4Ic\r\n"
"BVvN3BIlc1ue2YRXEDlxY5b0r8N4XceMgKmW18OHApZxfl8uPDauWZLXOgl4uepv\r\n"
"whZC3EuWrSyyICNhLY21Ah7hbIEBPF3L3ZsOwC+UErL+dXWLdB56Jgy3gZaBeW7b\r\n"
"vDrEnocJbqCm7IukhXHOBK8CgYEAwqdHB0hqyNSzIOGY7v9abzB6pUdA3BZiQvEs\r\n"
"3LjHVd4HPJ2x0N8CgrBIWOE0q8+0hSMmeE96WW/7jD3fPWwCR5zlXknxBQsfv0gP\r\n"
"3BC5PR0Qdypz+d+9zfMf625kyit4T/hzwhDveZUzHnk1Cf+IG7Q+TOEnLnWAWBED\r\n"
"ISOWmrUCgYAFEmRxgwAc/u+D6t0syCwAYh6POtscq9Y0i9GyWk89NzgC4NdwwbBH\r\n"
"4AgahOxIxXx2gxJnq3yfkJfIjwf0s2DyP0kY2y6Ua1OeomPeY9mrIS4tCuDQ6LrE\r\n"
"TB6l9VGoxJL4fyHnZb8L5gGvnB1bbD8cL6YPaDiOhcRseC9vBiEuVg==\r\n"
"-----END RSA PRIVATE KEY-----\r\n";
const char mbedtls_test_cli_crt_rsa[] =
"-----BEGIN CERTIFICATE-----\r\n"
"MIIDPzCCAiegAwIBAgIBBDANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER\r\n"
"MA8GA1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n"
"MTEwMjEyMTQ0NDA3WhcNMjEwMjEyMTQ0NDA3WjA8MQswCQYDVQQGEwJOTDERMA8G\r\n"
"A1UEChMIUG9sYXJTU0wxGjAYBgNVBAMTEVBvbGFyU1NMIENsaWVudCAyMIIBIjAN\r\n"
"BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyHTEzLn5tXnpRdkUYLB9u5Pyax6f\r\n"
"M60Nj4o8VmXl3ETZzGaFB9X4J7BKNdBjngpuG7fa8H6r7gwQk4ZJGDTzqCrSV/Uu\r\n"
"1C93KYRhTYJQj6eVSHD1bk2y1RPD0hrt5kPqQhTrdOrA7R/UV06p86jt0uDBMHEw\r\n"
"MjDV0/YI0FZPRo7yX/k9Z5GIMC5Cst99++UMd//sMcB4j7/Cf8qtbCHWjdmLao5v\r\n"
"4Jv4EFbMs44TFeY0BGbH7vk2DmqV9gmaBmf0ZXH4yqSxJeD+PIs1BGe64E92hfx/\r\n"
"/DZrtenNLQNiTrM9AM+vdqBpVoNq0qjU51Bx5rU2BXcFbXvI5MT9TNUhXwIDAQAB\r\n"
"o00wSzAJBgNVHRMEAjAAMB0GA1UdDgQWBBRxoQBzckAvVHZeM/xSj7zx3WtGITAf\r\n"
"BgNVHSMEGDAWgBS0WuSls97SUva51aaVD+s+vMf9/zANBgkqhkiG9w0BAQUFAAOC\r\n"
"AQEAAn86isAM8X+mVwJqeItt6E9slhEQbAofyk+diH1Lh8Y9iLlWQSKbw/UXYjx5\r\n"
"LLPZcniovxIcARC/BjyZR9g3UwTHNGNm+rwrqa15viuNOFBchykX/Orsk02EH7NR\r\n"
"Alw5WLPorYjED6cdVQgBl9ot93HdJogRiXCxErM7NC8/eP511mjq+uLDjLKH8ZPQ\r\n"
"8I4ekHJnroLsDkIwXKGIsvIBHQy2ac/NwHLCQOK6mfum1pRx52V4Utu5dLLjD5bM\r\n"
"xOBC7KU4xZKuMXXZM6/93Yb51K/J4ahf1TxJlTWXtnzDr9saEYdNy2SKY/6ZiDNH\r\n"
"D+stpAKiQLAWaAusIWKYEyw9MQ==\r\n"
"-----END CERTIFICATE-----\r\n";
const char mbedtls_test_cli_key_rsa[] =
"-----BEGIN RSA PRIVATE KEY-----\r\n"
"MIIEpAIBAAKCAQEAyHTEzLn5tXnpRdkUYLB9u5Pyax6fM60Nj4o8VmXl3ETZzGaF\r\n"
"B9X4J7BKNdBjngpuG7fa8H6r7gwQk4ZJGDTzqCrSV/Uu1C93KYRhTYJQj6eVSHD1\r\n"
"bk2y1RPD0hrt5kPqQhTrdOrA7R/UV06p86jt0uDBMHEwMjDV0/YI0FZPRo7yX/k9\r\n"
"Z5GIMC5Cst99++UMd//sMcB4j7/Cf8qtbCHWjdmLao5v4Jv4EFbMs44TFeY0BGbH\r\n"
"7vk2DmqV9gmaBmf0ZXH4yqSxJeD+PIs1BGe64E92hfx//DZrtenNLQNiTrM9AM+v\r\n"
"dqBpVoNq0qjU51Bx5rU2BXcFbXvI5MT9TNUhXwIDAQABAoIBAGdNtfYDiap6bzst\r\n"
"yhCiI8m9TtrhZw4MisaEaN/ll3XSjaOG2dvV6xMZCMV+5TeXDHOAZnY18Yi18vzz\r\n"
"4Ut2TnNFzizCECYNaA2fST3WgInnxUkV3YXAyP6CNxJaCmv2aA0yFr2kFVSeaKGt\r\n"
"ymvljNp2NVkvm7Th8fBQBO7I7AXhz43k0mR7XmPgewe8ApZOG3hstkOaMvbWAvWA\r\n"
"zCZupdDjZYjOJqlA4eEA4H8/w7F83r5CugeBE8LgEREjLPiyejrU5H1fubEY+h0d\r\n"
"l5HZBJ68ybTXfQ5U9o/QKA3dd0toBEhhdRUDGzWtjvwkEQfqF1reGWj/tod/gCpf\r\n"
"DFi6X0ECgYEA4wOv/pjSC3ty6TuOvKX2rOUiBrLXXv2JSxZnMoMiWI5ipLQt+RYT\r\n"
"VPafL/m7Dn6MbwjayOkcZhBwk5CNz5A6Q4lJ64Mq/lqHznRCQQ2Mc1G8eyDF/fYL\r\n"
"Ze2pLvwP9VD5jTc2miDfw+MnvJhywRRLcemDFP8k4hQVtm8PMp3ZmNECgYEA4gz7\r\n"
"wzObR4gn8ibe617uQPZjWzUj9dUHYd+in1gwBCIrtNnaRn9I9U/Q6tegRYpii4ys\r\n"
"c176NmU+umy6XmuSKV5qD9bSpZWG2nLFnslrN15Lm3fhZxoeMNhBaEDTnLT26yoi\r\n"
"33gp0mSSWy94ZEqipms+ULF6sY1ZtFW6tpGFoy8CgYAQHhnnvJflIs2ky4q10B60\r\n"
"ZcxFp3rtDpkp0JxhFLhiizFrujMtZSjYNm5U7KkgPVHhLELEUvCmOnKTt4ap/vZ0\r\n"
"BxJNe1GZH3pW6SAvGDQpl9sG7uu/vTFP+lCxukmzxB0DrrDcvorEkKMom7ZCCRvW\r\n"
"KZsZ6YeH2Z81BauRj218kQKBgQCUV/DgKP2985xDTT79N08jUo3hTP5MVYCCuj/+\r\n"
"UeEw1TvZcx3LJby7P6Xad6a1/BqveaGyFKIfEFIaBUBItk801sDDpDaYc4gL00Xc\r\n"
"7lFuBHOZkxJYlss5QrGpuOEl9ZwUt5IrFLBdYaKqNHzNVC1pCPfb/JyH6Dr2HUxq\r\n"
"gxUwAQKBgQCcU6G2L8AG9d9c0UpOyL1tMvFe5Ttw0KjlQVdsh1MP6yigYo9DYuwu\r\n"
"bHFVW2r0dBTqegP2/KTOxKzaHfC1qf0RGDsUoJCNJrd1cwoCLG8P2EF4w3OBrKqv\r\n"
"8u4ytY0F+Vlanj5lm3TaoHSVF1+NWPyOTiwevIECGKwSxvlki4fDAA==\r\n"
"-----END RSA PRIVATE KEY-----\r\n";
const size_t mbedtls_test_ca_crt_rsa_len = sizeof( mbedtls_test_ca_crt_rsa );
const size_t mbedtls_test_ca_key_rsa_len = sizeof( mbedtls_test_ca_key_rsa );
const size_t mbedtls_test_ca_pwd_rsa_len = sizeof( mbedtls_test_ca_pwd_rsa ) - 1;
const size_t mbedtls_test_srv_crt_rsa_len = sizeof( mbedtls_test_srv_crt_rsa );
const size_t mbedtls_test_srv_key_rsa_len = sizeof( mbedtls_test_srv_key_rsa );
const size_t mbedtls_test_cli_crt_rsa_len = sizeof( mbedtls_test_cli_crt_rsa );
const size_t mbedtls_test_cli_key_rsa_len = sizeof( mbedtls_test_cli_key_rsa );
#else
#define TEST_CA_CRT_RSA
#endif /* MBEDTLS_RSA_C */
#if defined(MBEDTLS_PEM_PARSE_C)
/* Concatenation of all available CA certificates */
const char mbedtls_test_cas_pem[] = TEST_CA_CRT_RSA TEST_CA_CRT_EC;
const size_t mbedtls_test_cas_pem_len = sizeof( mbedtls_test_cas_pem );
#endif
/* List of all available CA certificates */
const char * mbedtls_test_cas[] = {
#if defined(MBEDTLS_RSA_C)
mbedtls_test_ca_crt_rsa,
#endif
#if defined(MBEDTLS_ECDSA_C)
mbedtls_test_ca_crt_ec,
#endif
NULL
};
const size_t mbedtls_test_cas_len[] = {
#if defined(MBEDTLS_RSA_C)
sizeof( mbedtls_test_ca_crt_rsa ),
#endif
#if defined(MBEDTLS_ECDSA_C)
sizeof( mbedtls_test_ca_crt_ec ),
#endif
0
};
#if defined(MBEDTLS_RSA_C)
const char *mbedtls_test_ca_crt = mbedtls_test_ca_crt_rsa;
const char *mbedtls_test_ca_key = mbedtls_test_ca_key_rsa;
const char *mbedtls_test_ca_pwd = mbedtls_test_ca_pwd_rsa;
const char *mbedtls_test_srv_crt = mbedtls_test_srv_crt_rsa;
const char *mbedtls_test_srv_key = mbedtls_test_srv_key_rsa;
const char *mbedtls_test_cli_crt = mbedtls_test_cli_crt_rsa;
const char *mbedtls_test_cli_key = mbedtls_test_cli_key_rsa;
const size_t mbedtls_test_ca_crt_len = sizeof( mbedtls_test_ca_crt_rsa );
const size_t mbedtls_test_ca_key_len = sizeof( mbedtls_test_ca_key_rsa );
const size_t mbedtls_test_ca_pwd_len = sizeof( mbedtls_test_ca_pwd_rsa ) - 1;
const size_t mbedtls_test_srv_crt_len = sizeof( mbedtls_test_srv_crt_rsa );
const size_t mbedtls_test_srv_key_len = sizeof( mbedtls_test_srv_key_rsa );
const size_t mbedtls_test_cli_crt_len = sizeof( mbedtls_test_cli_crt_rsa );
const size_t mbedtls_test_cli_key_len = sizeof( mbedtls_test_cli_key_rsa );
#else /* ! MBEDTLS_RSA_C, so MBEDTLS_ECDSA_C */
const char *mbedtls_test_ca_crt = mbedtls_test_ca_crt_ec;
const char *mbedtls_test_ca_key = mbedtls_test_ca_key_ec;
const char *mbedtls_test_ca_pwd = mbedtls_test_ca_pwd_ec;
const char *mbedtls_test_srv_crt = mbedtls_test_srv_crt_ec;
const char *mbedtls_test_srv_key = mbedtls_test_srv_key_ec;
const char *mbedtls_test_cli_crt = mbedtls_test_cli_crt_ec;
const char *mbedtls_test_cli_key = mbedtls_test_cli_key_ec;
const size_t mbedtls_test_ca_crt_len = sizeof( mbedtls_test_ca_crt_ec );
const size_t mbedtls_test_ca_key_len = sizeof( mbedtls_test_ca_key_ec );
const size_t mbedtls_test_ca_pwd_len = sizeof( mbedtls_test_ca_pwd_ec ) - 1;
const size_t mbedtls_test_srv_crt_len = sizeof( mbedtls_test_srv_crt_ec );
const size_t mbedtls_test_srv_key_len = sizeof( mbedtls_test_srv_key_ec );
const size_t mbedtls_test_cli_crt_len = sizeof( mbedtls_test_cli_crt_ec );
const size_t mbedtls_test_cli_key_len = sizeof( mbedtls_test_cli_key_ec );
#endif /* MBEDTLS_RSA_C */
#endif /* MBEDTLS_CERTS_C */
#else
#endif
/**
* \file cipher.c
*
* \brief Generic cipher wrapper for mbed TLS
*
* \author Adriaan de Jong <dejong@fox-it.com>
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed 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.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_CIPHER_C)
#include "mbedtls/cipher.h"
#include "mbedtls/cipher_internal.h"
#include <stdlib.h>
#include <string.h>
#if defined(MBEDTLS_GCM_C)
#include "mbedtls/gcm.h"
#endif
#if defined(MBEDTLS_CCM_C)
#include "mbedtls/ccm.h"
#endif
#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER)
#define MBEDTLS_CIPHER_MODE_STREAM
#endif
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n ) {
volatile unsigned char *p = v; while( n-- ) *p++ = 0;
}
static int supported_init = 0;
const int *mbedtls_cipher_list( void )
{
const mbedtls_cipher_definition_t *def;
int *type;
if( ! supported_init )
{
def = mbedtls_cipher_definitions;
type = mbedtls_cipher_supported;
while( def->type != 0 )
*type++ = (*def++).type;
*type = 0;
supported_init = 1;
}
return( mbedtls_cipher_supported );
}
const mbedtls_cipher_info_t *mbedtls_cipher_info_from_type( const mbedtls_cipher_type_t cipher_type )
{
const mbedtls_cipher_definition_t *def;
for( def = mbedtls_cipher_definitions; def->info != NULL; def++ )
if( def->type == cipher_type )
return( def->info );
return( NULL );
}
const mbedtls_cipher_info_t *mbedtls_cipher_info_from_string( const char *cipher_name )
{
const mbedtls_cipher_definition_t *def;
if( NULL == cipher_name )
return( NULL );
for( def = mbedtls_cipher_definitions; def->info != NULL; def++ )
if( ! strcmp( def->info->name, cipher_name ) )
return( def->info );
return( NULL );
}
const mbedtls_cipher_info_t *mbedtls_cipher_info_from_values( const mbedtls_cipher_id_t cipher_id,
int key_bitlen,
const mbedtls_cipher_mode_t mode )
{
const mbedtls_cipher_definition_t *def;
for( def = mbedtls_cipher_definitions; def->info != NULL; def++ )
if( def->info->base->cipher == cipher_id &&
def->info->key_bitlen == (unsigned) key_bitlen &&
def->info->mode == mode )
return( def->info );
return( NULL );
}
void mbedtls_cipher_init( mbedtls_cipher_context_t *ctx )
{
memset( ctx, 0, sizeof( mbedtls_cipher_context_t ) );
}
void mbedtls_cipher_free( mbedtls_cipher_context_t *ctx )
{
if( ctx == NULL )
return;
if( ctx->cipher_ctx )
ctx->cipher_info->base->ctx_free_func( ctx->cipher_ctx );
mbedtls_zeroize( ctx, sizeof(mbedtls_cipher_context_t) );
}
int mbedtls_cipher_setup( mbedtls_cipher_context_t *ctx, const mbedtls_cipher_info_t *cipher_info )
{
if( NULL == cipher_info || NULL == ctx )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
memset( ctx, 0, sizeof( mbedtls_cipher_context_t ) );
if( NULL == ( ctx->cipher_ctx = cipher_info->base->ctx_alloc_func() ) )
return( MBEDTLS_ERR_CIPHER_ALLOC_FAILED );
ctx->cipher_info = cipher_info;
#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
/*
* Ignore possible errors caused by a cipher mode that doesn't use padding
*/
#if defined(MBEDTLS_CIPHER_PADDING_PKCS7)
(void) mbedtls_cipher_set_padding_mode( ctx, MBEDTLS_PADDING_PKCS7 );
#else
(void) mbedtls_cipher_set_padding_mode( ctx, MBEDTLS_PADDING_NONE );
#endif
#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */
return( 0 );
}
int mbedtls_cipher_setkey( mbedtls_cipher_context_t *ctx, const unsigned char *key,
int key_bitlen, const mbedtls_operation_t operation )
{
if( NULL == ctx || NULL == ctx->cipher_info )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
if( ( ctx->cipher_info->flags & MBEDTLS_CIPHER_VARIABLE_KEY_LEN ) == 0 &&
(int) ctx->cipher_info->key_bitlen != key_bitlen )
{
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
}
ctx->key_bitlen = key_bitlen;
ctx->operation = operation;
/*
* For CFB and CTR mode always use the encryption key schedule
*/
if( MBEDTLS_ENCRYPT == operation ||
MBEDTLS_MODE_CFB == ctx->cipher_info->mode ||
MBEDTLS_MODE_CTR == ctx->cipher_info->mode )
{
return ctx->cipher_info->base->setkey_enc_func( ctx->cipher_ctx, key,
ctx->key_bitlen );
}
if( MBEDTLS_DECRYPT == operation )
return ctx->cipher_info->base->setkey_dec_func( ctx->cipher_ctx, key,
ctx->key_bitlen );
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
}
int mbedtls_cipher_set_iv( mbedtls_cipher_context_t *ctx,
const unsigned char *iv, size_t iv_len )
{
size_t actual_iv_size;
if( NULL == ctx || NULL == ctx->cipher_info || NULL == iv )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
/* avoid buffer overflow in ctx->iv */
if( iv_len > MBEDTLS_MAX_IV_LENGTH )
return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
if( ( ctx->cipher_info->flags & MBEDTLS_CIPHER_VARIABLE_IV_LEN ) != 0 )
actual_iv_size = iv_len;
else
{
actual_iv_size = ctx->cipher_info->iv_size;
/* avoid reading past the end of input buffer */
if( actual_iv_size > iv_len )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
}
memcpy( ctx->iv, iv, actual_iv_size );
ctx->iv_size = actual_iv_size;
return( 0 );
}
int mbedtls_cipher_reset( mbedtls_cipher_context_t *ctx )
{
if( NULL == ctx || NULL == ctx->cipher_info )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
ctx->unprocessed_len = 0;
return( 0 );
}
#if defined(MBEDTLS_GCM_C)
int mbedtls_cipher_update_ad( mbedtls_cipher_context_t *ctx,
const unsigned char *ad, size_t ad_len )
{
if( NULL == ctx || NULL == ctx->cipher_info )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
{
return mbedtls_gcm_starts( (mbedtls_gcm_context *) ctx->cipher_ctx, ctx->operation,
ctx->iv, ctx->iv_size, ad, ad_len );
}
return( 0 );
}
#endif /* MBEDTLS_GCM_C */
int mbedtls_cipher_update( mbedtls_cipher_context_t *ctx, const unsigned char *input,
size_t ilen, unsigned char *output, size_t *olen )
{
int ret;
if( NULL == ctx || NULL == ctx->cipher_info || NULL == olen )
{
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
}
*olen = 0;
if( ctx->cipher_info->mode == MBEDTLS_MODE_ECB )
{
if( ilen != mbedtls_cipher_get_block_size( ctx ) )
return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED );
*olen = ilen;
if( 0 != ( ret = ctx->cipher_info->base->ecb_func( ctx->cipher_ctx,
ctx->operation, input, output ) ) )
{
return( ret );
}
return( 0 );
}
#if defined(MBEDTLS_GCM_C)
if( ctx->cipher_info->mode == MBEDTLS_MODE_GCM )
{
*olen = ilen;
return mbedtls_gcm_update( (mbedtls_gcm_context *) ctx->cipher_ctx, ilen, input,
output );
}
#endif
if( input == output &&
( ctx->unprocessed_len != 0 || ilen % mbedtls_cipher_get_block_size( ctx ) ) )
{
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
}
#if defined(MBEDTLS_CIPHER_MODE_CBC)
if( ctx->cipher_info->mode == MBEDTLS_MODE_CBC )
{
size_t copy_len = 0;
/*
* If there is not enough data for a full block, cache it.
*/
if( ( ctx->operation == MBEDTLS_DECRYPT &&
ilen + ctx->unprocessed_len <= mbedtls_cipher_get_block_size( ctx ) ) ||
( ctx->operation == MBEDTLS_ENCRYPT &&
ilen + ctx->unprocessed_len < mbedtls_cipher_get_block_size( ctx ) ) )
{
memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ), input,
ilen );
ctx->unprocessed_len += ilen;
return( 0 );
}
/*
* Process cached data first
*/
if( ctx->unprocessed_len != 0 )
{
copy_len = mbedtls_cipher_get_block_size( ctx ) - ctx->unprocessed_len;
memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ), input,
copy_len );
if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx,
ctx->operation, mbedtls_cipher_get_block_size( ctx ), ctx->iv,
ctx->unprocessed_data, output ) ) )
{
return( ret );
}
*olen += mbedtls_cipher_get_block_size( ctx );
output += mbedtls_cipher_get_block_size( ctx );
ctx->unprocessed_len = 0;
input += copy_len;
ilen -= copy_len;
}
/*
* Cache final, incomplete block
*/
if( 0 != ilen )
{
copy_len = ilen % mbedtls_cipher_get_block_size( ctx );
if( copy_len == 0 && ctx->operation == MBEDTLS_DECRYPT )
copy_len = mbedtls_cipher_get_block_size( ctx );
memcpy( ctx->unprocessed_data, &( input[ilen - copy_len] ),
copy_len );
ctx->unprocessed_len += copy_len;
ilen -= copy_len;
}
/*
* Process remaining full blocks
*/
if( ilen )
{
if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx,
ctx->operation, ilen, ctx->iv, input, output ) ) )
{
return( ret );
}
*olen += ilen;
}
return( 0 );
}
#endif /* MBEDTLS_CIPHER_MODE_CBC */
#if defined(MBEDTLS_CIPHER_MODE_CFB)
if( ctx->cipher_info->mode == MBEDTLS_MODE_CFB )
{
if( 0 != ( ret = ctx->cipher_info->base->cfb_func( ctx->cipher_ctx,
ctx->operation, ilen, &ctx->unprocessed_len, ctx->iv,
input, output ) ) )
{
return( ret );
}
*olen = ilen;
return( 0 );
}
#endif /* MBEDTLS_CIPHER_MODE_CFB */
#if defined(MBEDTLS_CIPHER_MODE_CTR)
if( ctx->cipher_info->mode == MBEDTLS_MODE_CTR )
{
if( 0 != ( ret = ctx->cipher_info->base->ctr_func( ctx->cipher_ctx,
ilen, &ctx->unprocessed_len, ctx->iv,
ctx->unprocessed_data, input, output ) ) )
{
return( ret );
}
*olen = ilen;
return( 0 );
}
#endif /* MBEDTLS_CIPHER_MODE_CTR */
#if defined(MBEDTLS_CIPHER_MODE_STREAM)
if( ctx->cipher_info->mode == MBEDTLS_MODE_STREAM )
{
if( 0 != ( ret = ctx->cipher_info->base->stream_func( ctx->cipher_ctx,
ilen, input, output ) ) )
{
return( ret );
}
*olen = ilen;
return( 0 );
}
#endif /* MBEDTLS_CIPHER_MODE_STREAM */
return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
}
#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
#if defined(MBEDTLS_CIPHER_PADDING_PKCS7)
/*
* PKCS7 (and PKCS5) padding: fill with ll bytes, with ll = padding_len
*/
static void add_pkcs_padding( unsigned char *output, size_t output_len,
size_t data_len )
{
size_t padding_len = output_len - data_len;
unsigned char i;
for( i = 0; i < padding_len; i++ )
output[data_len + i] = (unsigned char) padding_len;
}
static int get_pkcs_padding( unsigned char *input, size_t input_len,
size_t *data_len )
{
size_t i, pad_idx;
unsigned char padding_len, bad = 0;
if( NULL == input || NULL == data_len )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
padding_len = input[input_len - 1];
*data_len = input_len - padding_len;
/* Avoid logical || since it results in a branch */
bad |= padding_len > input_len;
bad |= padding_len == 0;
/* The number of bytes checked must be independent of padding_len,
* so pick input_len, which is usually 8 or 16 (one block) */
pad_idx = input_len - padding_len;
for( i = 0; i < input_len; i++ )
bad |= ( input[i] ^ padding_len ) * ( i >= pad_idx );
return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) );
}
#endif /* MBEDTLS_CIPHER_PADDING_PKCS7 */
#if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS)
/*
* One and zeros padding: fill with 80 00 ... 00
*/
static void add_one_and_zeros_padding( unsigned char *output,
size_t output_len, size_t data_len )
{
size_t padding_len = output_len - data_len;
unsigned char i = 0;
output[data_len] = 0x80;
for( i = 1; i < padding_len; i++ )
output[data_len + i] = 0x00;
}
static int get_one_and_zeros_padding( unsigned char *input, size_t input_len,
size_t *data_len )
{
size_t i;
unsigned char done = 0, prev_done, bad;
if( NULL == input || NULL == data_len )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
bad = 0xFF;
*data_len = 0;
for( i = input_len; i > 0; i-- )
{
prev_done = done;
done |= ( input[i-1] != 0 );
*data_len |= ( i - 1 ) * ( done != prev_done );
bad &= ( input[i-1] ^ 0x80 ) | ( done == prev_done );
}
return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) );
}
#endif /* MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS */
#if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN)
/*
* Zeros and len padding: fill with 00 ... 00 ll, where ll is padding length
*/
static void add_zeros_and_len_padding( unsigned char *output,
size_t output_len, size_t data_len )
{
size_t padding_len = output_len - data_len;
unsigned char i = 0;
for( i = 1; i < padding_len; i++ )
output[data_len + i - 1] = 0x00;
output[output_len - 1] = (unsigned char) padding_len;
}
static int get_zeros_and_len_padding( unsigned char *input, size_t input_len,
size_t *data_len )
{
size_t i, pad_idx;
unsigned char padding_len, bad = 0;
if( NULL == input || NULL == data_len )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
padding_len = input[input_len - 1];
*data_len = input_len - padding_len;
/* Avoid logical || since it results in a branch */
bad |= padding_len > input_len;
bad |= padding_len == 0;
/* The number of bytes checked must be independent of padding_len */
pad_idx = input_len - padding_len;
for( i = 0; i < input_len - 1; i++ )
bad |= input[i] * ( i >= pad_idx );
return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) );
}
#endif /* MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN */
#if defined(MBEDTLS_CIPHER_PADDING_ZEROS)
/*
* Zero padding: fill with 00 ... 00
*/
static void add_zeros_padding( unsigned char *output,
size_t output_len, size_t data_len )
{
size_t i;
for( i = data_len; i < output_len; i++ )
output[i] = 0x00;
}
static int get_zeros_padding( unsigned char *input, size_t input_len,
size_t *data_len )
{
size_t i;
unsigned char done = 0, prev_done;
if( NULL == input || NULL == data_len )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
*data_len = 0;
for( i = input_len; i > 0; i-- )
{
prev_done = done;
done |= ( input[i-1] != 0 );
*data_len |= i * ( done != prev_done );
}
return( 0 );
}
#endif /* MBEDTLS_CIPHER_PADDING_ZEROS */
/*
* No padding: don't pad :)
*
* There is no add_padding function (check for NULL in mbedtls_cipher_finish)
* but a trivial get_padding function
*/
static int get_no_padding( unsigned char *input, size_t input_len,
size_t *data_len )
{
if( NULL == input || NULL == data_len )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
*data_len = input_len;
return( 0 );
}
#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */
int mbedtls_cipher_finish( mbedtls_cipher_context_t *ctx,
unsigned char *output, size_t *olen )
{
if( NULL == ctx || NULL == ctx->cipher_info || NULL == olen )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
*olen = 0;
if( MBEDTLS_MODE_CFB == ctx->cipher_info->mode ||
MBEDTLS_MODE_CTR == ctx->cipher_info->mode ||
MBEDTLS_MODE_GCM == ctx->cipher_info->mode ||
MBEDTLS_MODE_STREAM == ctx->cipher_info->mode )
{
return( 0 );
}
if( MBEDTLS_MODE_ECB == ctx->cipher_info->mode )
{
if( ctx->unprocessed_len != 0 )
return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED );
return( 0 );
}
#if defined(MBEDTLS_CIPHER_MODE_CBC)
if( MBEDTLS_MODE_CBC == ctx->cipher_info->mode )
{
int ret = 0;
if( MBEDTLS_ENCRYPT == ctx->operation )
{
/* check for 'no padding' mode */
if( NULL == ctx->add_padding )
{
if( 0 != ctx->unprocessed_len )
return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED );
return( 0 );
}
ctx->add_padding( ctx->unprocessed_data, mbedtls_cipher_get_iv_size( ctx ),
ctx->unprocessed_len );
}
else if( mbedtls_cipher_get_block_size( ctx ) != ctx->unprocessed_len )
{
/*
* For decrypt operations, expect a full block,
* or an empty block if no padding
*/
if( NULL == ctx->add_padding && 0 == ctx->unprocessed_len )
return( 0 );
return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED );
}
/* cipher block */
if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx,
ctx->operation, mbedtls_cipher_get_block_size( ctx ), ctx->iv,
ctx->unprocessed_data, output ) ) )
{
return( ret );
}
/* Set output size for decryption */
if( MBEDTLS_DECRYPT == ctx->operation )
return ctx->get_padding( output, mbedtls_cipher_get_block_size( ctx ),
olen );
/* Set output size for encryption */
*olen = mbedtls_cipher_get_block_size( ctx );
return( 0 );
}
#else
((void) output);
#endif /* MBEDTLS_CIPHER_MODE_CBC */
return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
}
#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
int mbedtls_cipher_set_padding_mode( mbedtls_cipher_context_t *ctx, mbedtls_cipher_padding_t mode )
{
if( NULL == ctx ||
MBEDTLS_MODE_CBC != ctx->cipher_info->mode )
{
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
}
switch( mode )
{
#if defined(MBEDTLS_CIPHER_PADDING_PKCS7)
case MBEDTLS_PADDING_PKCS7:
ctx->add_padding = add_pkcs_padding;
ctx->get_padding = get_pkcs_padding;
break;
#endif
#if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS)
case MBEDTLS_PADDING_ONE_AND_ZEROS:
ctx->add_padding = add_one_and_zeros_padding;
ctx->get_padding = get_one_and_zeros_padding;
break;
#endif
#if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN)
case MBEDTLS_PADDING_ZEROS_AND_LEN:
ctx->add_padding = add_zeros_and_len_padding;
ctx->get_padding = get_zeros_and_len_padding;
break;
#endif
#if defined(MBEDTLS_CIPHER_PADDING_ZEROS)
case MBEDTLS_PADDING_ZEROS:
ctx->add_padding = add_zeros_padding;
ctx->get_padding = get_zeros_padding;
break;
#endif
case MBEDTLS_PADDING_NONE:
ctx->add_padding = NULL;
ctx->get_padding = get_no_padding;
break;
default:
return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
}
return( 0 );
}
#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */
#if defined(MBEDTLS_GCM_C)
int mbedtls_cipher_write_tag( mbedtls_cipher_context_t *ctx,
unsigned char *tag, size_t tag_len )
{
if( NULL == ctx || NULL == ctx->cipher_info || NULL == tag )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
if( MBEDTLS_ENCRYPT != ctx->operation )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
return mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx, tag, tag_len );
return( 0 );
}
int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx,
const unsigned char *tag, size_t tag_len )
{
int ret;
if( NULL == ctx || NULL == ctx->cipher_info ||
MBEDTLS_DECRYPT != ctx->operation )
{
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
}
if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
{
unsigned char check_tag[16];
size_t i;
int diff;
if( tag_len > sizeof( check_tag ) )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
if( 0 != ( ret = mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx,
check_tag, tag_len ) ) )
{
return( ret );
}
/* Check the tag in "constant-time" */
for( diff = 0, i = 0; i < tag_len; i++ )
diff |= tag[i] ^ check_tag[i];
if( diff != 0 )
return( MBEDTLS_ERR_CIPHER_AUTH_FAILED );
return( 0 );
}
return( 0 );
}
#endif /* MBEDTLS_GCM_C */
/*
* Packet-oriented wrapper for non-AEAD modes
*/
int mbedtls_cipher_crypt( mbedtls_cipher_context_t *ctx,
const unsigned char *iv, size_t iv_len,
const unsigned char *input, size_t ilen,
unsigned char *output, size_t *olen )
{
int ret;
size_t finish_olen;
if( ( ret = mbedtls_cipher_set_iv( ctx, iv, iv_len ) ) != 0 )
return( ret );
if( ( ret = mbedtls_cipher_reset( ctx ) ) != 0 )
return( ret );
if( ( ret = mbedtls_cipher_update( ctx, input, ilen, output, olen ) ) != 0 )
return( ret );
if( ( ret = mbedtls_cipher_finish( ctx, output + *olen, &finish_olen ) ) != 0 )
return( ret );
*olen += finish_olen;
return( 0 );
}
#if defined(MBEDTLS_CIPHER_MODE_AEAD)
/*
* Packet-oriented encryption for AEAD modes
*/
int mbedtls_cipher_auth_encrypt( mbedtls_cipher_context_t *ctx,
const unsigned char *iv, size_t iv_len,
const unsigned char *ad, size_t ad_len,
const unsigned char *input, size_t ilen,
unsigned char *output, size_t *olen,
unsigned char *tag, size_t tag_len )
{
#if defined(MBEDTLS_GCM_C)
if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
{
*olen = ilen;
return( mbedtls_gcm_crypt_and_tag( ctx->cipher_ctx, MBEDTLS_GCM_ENCRYPT, ilen,
iv, iv_len, ad, ad_len, input, output,
tag_len, tag ) );
}
#endif /* MBEDTLS_GCM_C */
#if defined(MBEDTLS_CCM_C)
if( MBEDTLS_MODE_CCM == ctx->cipher_info->mode )
{
*olen = ilen;
return( mbedtls_ccm_encrypt_and_tag( ctx->cipher_ctx, ilen,
iv, iv_len, ad, ad_len, input, output,
tag, tag_len ) );
}
#endif /* MBEDTLS_CCM_C */
return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
}
/*
* Packet-oriented decryption for AEAD modes
*/
int mbedtls_cipher_auth_decrypt( mbedtls_cipher_context_t *ctx,
const unsigned char *iv, size_t iv_len,
const unsigned char *ad, size_t ad_len,
const unsigned char *input, size_t ilen,
unsigned char *output, size_t *olen,
const unsigned char *tag, size_t tag_len )
{
#if defined(MBEDTLS_GCM_C)
if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
{
int ret;
*olen = ilen;
ret = mbedtls_gcm_auth_decrypt( ctx->cipher_ctx, ilen,
iv, iv_len, ad, ad_len,
tag, tag_len, input, output );
if( ret == MBEDTLS_ERR_GCM_AUTH_FAILED )
ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
return( ret );
}
#endif /* MBEDTLS_GCM_C */
#if defined(MBEDTLS_CCM_C)
if( MBEDTLS_MODE_CCM == ctx->cipher_info->mode )
{
int ret;
*olen = ilen;
ret = mbedtls_ccm_auth_decrypt( ctx->cipher_ctx, ilen,
iv, iv_len, ad, ad_len,
input, output, tag, tag_len );
if( ret == MBEDTLS_ERR_CCM_AUTH_FAILED )
ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
return( ret );
}
#endif /* MBEDTLS_CCM_C */
return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
}
#endif /* MBEDTLS_CIPHER_MODE_AEAD */
#endif /* MBEDTLS_CIPHER_C */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment