Release Mbed Crypto 0.1.0a
diff --git a/library/Makefile b/library/Makefile
new file mode 100644
index 0000000..9151662
--- /dev/null
+++ b/library/Makefile
@@ -0,0 +1,76 @@
+CFLAGS ?= -O2 -I../include
+WARNING_CFLAGS ?= \
+ -Werror -Wall -Wextra \
+ -Wno-unused-function \
+ -Wno-overlength-strings \
+ -Wdeclaration-after-statement \
+# Don't delete this line.
+
+OBJS_CRYPTO := \
+ aes.o \
+ aesni.o \
+ arc4.o \
+ asn1parse.o \
+ asn1write.o \
+ base64.o \
+ bignum.o \
+ blowfish.o \
+ camellia.o \
+ ccm.o \
+ cipher.o \
+ cipher_wrap.o \
+ cmac.o \
+ ctr_drbg.o \
+ des.o \
+ ecdsa.o \
+ ecp.o \
+ ecp_curves.o \
+ entropy.o \
+ entropy_poll.o \
+ gcm.o \
+ hmac_drbg.o \
+ md.o \
+ md2.o \
+ md4.o \
+ md5.o \
+ md_wrap.o \
+ oid.o \
+ pem.o \
+ pk.o \
+ pk_wrap.o \
+ pkcs12.o \
+ pkcs5.o \
+ pkparse.o \
+ pkwrite.o \
+ platform.o \
+ platform_util.o \
+ psa_crypto.o \
+ ripemd160.o \
+ rsa_internal.o \
+ rsa.o \
+ sha1.o \
+ sha256.o \
+ sha512.o \
+ xtea.o \
+# Don't delete this line.
+
+.SILENT:
+
+.PHONY: all static clean
+
+all: static
+
+static: libmbedcrypto.a
+
+libmbedcrypto.a: $(OBJS_CRYPTO)
+ echo " AR $@"
+ $(AR) -rc $@ $(OBJS_CRYPTO)
+ echo " RL $@"
+ $(AR) -s $@
+
+.c.o:
+ echo " CC $<"
+ $(CC) $(CFLAGS) $(WARNING_CFLAGS) -c $<
+
+clean:
+ rm -f *.o libmbedcrypto.a
diff --git a/library/aes.c b/library/aes.c
new file mode 100644
index 0000000..4841243
--- /dev/null
+++ b/library/aes.c
@@ -0,0 +1,1574 @@
+/*
+ * 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 Crypto (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(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_AES_C)
+
+#include <string.h>
+
+#include "mbedcrypto/aes.h"
+#include "mbedcrypto/platform_util.h"
+#if defined(MBEDCRYPTO_PADLOCK_C)
+#include "mbedcrypto/padlock.h"
+#endif
+#if defined(MBEDCRYPTO_AESNI_C)
+#include "mbedcrypto/aesni.h"
+#endif
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#include <stdio.h>
+#define mbedcrypto_printf printf
+#endif /* MBEDCRYPTO_PLATFORM_C */
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#if !defined(MBEDCRYPTO_AES_ALT)
+
+/*
+ * 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(MBEDCRYPTO_PADLOCK_C) && \
+ ( defined(MBEDCRYPTO_HAVE_X86) || defined(MBEDCRYPTO_PADLOCK_ALIGN16) )
+static int aes_padlock_ace = -1;
+#endif
+
+#if defined(MBEDCRYPTO_AES_ROM_TABLES)
+/*
+ * Forward S-box
+ */
+static const unsigned char FSb[256] =
+{
+ 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] = { FT };
+#undef V
+
+#if !defined(MBEDCRYPTO_AES_FEWER_TABLES)
+
+#define V(a,b,c,d) 0x##b##c##d##a
+static const uint32_t FT1[256] = { FT };
+#undef V
+
+#define V(a,b,c,d) 0x##c##d##a##b
+static const uint32_t FT2[256] = { FT };
+#undef V
+
+#define V(a,b,c,d) 0x##d##a##b##c
+static const uint32_t FT3[256] = { FT };
+#undef V
+
+#endif /* !MBEDCRYPTO_AES_FEWER_TABLES */
+
+#undef FT
+
+/*
+ * Reverse S-box
+ */
+static const unsigned char RSb[256] =
+{
+ 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] = { RT };
+#undef V
+
+#if !defined(MBEDCRYPTO_AES_FEWER_TABLES)
+
+#define V(a,b,c,d) 0x##b##c##d##a
+static const uint32_t RT1[256] = { RT };
+#undef V
+
+#define V(a,b,c,d) 0x##c##d##a##b
+static const uint32_t RT2[256] = { RT };
+#undef V
+
+#define V(a,b,c,d) 0x##d##a##b##c
+static const uint32_t RT3[256] = { RT };
+#undef V
+
+#endif /* !MBEDCRYPTO_AES_FEWER_TABLES */
+
+#undef RT
+
+/*
+ * Round constants
+ */
+static const uint32_t RCON[10] =
+{
+ 0x00000001, 0x00000002, 0x00000004, 0x00000008,
+ 0x00000010, 0x00000020, 0x00000040, 0x00000080,
+ 0x0000001B, 0x00000036
+};
+
+#else /* MBEDCRYPTO_AES_ROM_TABLES */
+
+/*
+ * Forward S-box & tables
+ */
+static unsigned char FSb[256];
+static uint32_t FT0[256];
+#if !defined(MBEDCRYPTO_AES_FEWER_TABLES)
+static uint32_t FT1[256];
+static uint32_t FT2[256];
+static uint32_t FT3[256];
+#endif /* !MBEDCRYPTO_AES_FEWER_TABLES */
+
+/*
+ * Reverse S-box & tables
+ */
+static unsigned char RSb[256];
+static uint32_t RT0[256];
+#if !defined(MBEDCRYPTO_AES_FEWER_TABLES)
+static uint32_t RT1[256];
+static uint32_t RT2[256];
+static uint32_t RT3[256];
+#endif /* !MBEDCRYPTO_AES_FEWER_TABLES */
+
+/*
+ * 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 );
+
+#if !defined(MBEDCRYPTO_AES_FEWER_TABLES)
+ FT1[i] = ROTL8( FT0[i] );
+ FT2[i] = ROTL8( FT1[i] );
+ FT3[i] = ROTL8( FT2[i] );
+#endif /* !MBEDCRYPTO_AES_FEWER_TABLES */
+
+ 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 );
+
+#if !defined(MBEDCRYPTO_AES_FEWER_TABLES)
+ RT1[i] = ROTL8( RT0[i] );
+ RT2[i] = ROTL8( RT1[i] );
+ RT3[i] = ROTL8( RT2[i] );
+#endif /* !MBEDCRYPTO_AES_FEWER_TABLES */
+ }
+}
+
+#undef ROTL8
+
+#endif /* MBEDCRYPTO_AES_ROM_TABLES */
+
+#if defined(MBEDCRYPTO_AES_FEWER_TABLES)
+
+#define ROTL8(x) ( (uint32_t)( ( x ) << 8 ) + (uint32_t)( ( x ) >> 24 ) )
+#define ROTL16(x) ( (uint32_t)( ( x ) << 16 ) + (uint32_t)( ( x ) >> 16 ) )
+#define ROTL24(x) ( (uint32_t)( ( x ) << 24 ) + (uint32_t)( ( x ) >> 8 ) )
+
+#define AES_RT0(idx) RT0[idx]
+#define AES_RT1(idx) ROTL8( RT0[idx] )
+#define AES_RT2(idx) ROTL16( RT0[idx] )
+#define AES_RT3(idx) ROTL24( RT0[idx] )
+
+#define AES_FT0(idx) FT0[idx]
+#define AES_FT1(idx) ROTL8( FT0[idx] )
+#define AES_FT2(idx) ROTL16( FT0[idx] )
+#define AES_FT3(idx) ROTL24( FT0[idx] )
+
+#else /* MBEDCRYPTO_AES_FEWER_TABLES */
+
+#define AES_RT0(idx) RT0[idx]
+#define AES_RT1(idx) RT1[idx]
+#define AES_RT2(idx) RT2[idx]
+#define AES_RT3(idx) RT3[idx]
+
+#define AES_FT0(idx) FT0[idx]
+#define AES_FT1(idx) FT1[idx]
+#define AES_FT2(idx) FT2[idx]
+#define AES_FT3(idx) FT3[idx]
+
+#endif /* MBEDCRYPTO_AES_FEWER_TABLES */
+
+void mbedcrypto_aes_init( mbedcrypto_aes_context *ctx )
+{
+ memset( ctx, 0, sizeof( mbedcrypto_aes_context ) );
+}
+
+void mbedcrypto_aes_free( mbedcrypto_aes_context *ctx )
+{
+ if( ctx == NULL )
+ return;
+
+ mbedcrypto_platform_zeroize( ctx, sizeof( mbedcrypto_aes_context ) );
+}
+
+/*
+ * AES key schedule (encryption)
+ */
+#if !defined(MBEDCRYPTO_AES_SETKEY_ENC_ALT)
+int mbedcrypto_aes_setkey_enc( mbedcrypto_aes_context *ctx, const unsigned char *key,
+ unsigned int keybits )
+{
+ unsigned int i;
+ uint32_t *RK;
+
+#if !defined(MBEDCRYPTO_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( MBEDCRYPTO_ERR_AES_INVALID_KEY_LENGTH );
+ }
+
+#if defined(MBEDCRYPTO_PADLOCK_C) && defined(MBEDCRYPTO_PADLOCK_ALIGN16)
+ if( aes_padlock_ace == -1 )
+ aes_padlock_ace = mbedcrypto_padlock_has_support( MBEDCRYPTO_PADLOCK_ACE );
+
+ if( aes_padlock_ace )
+ ctx->rk = RK = MBEDCRYPTO_PADLOCK_ALIGN16( ctx->buf );
+ else
+#endif
+ ctx->rk = RK = ctx->buf;
+
+#if defined(MBEDCRYPTO_AESNI_C) && defined(MBEDCRYPTO_HAVE_X86_64)
+ if( mbedcrypto_aesni_has_support( MBEDCRYPTO_AESNI_AES ) )
+ return( mbedcrypto_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) FSb[ ( RK[3] >> 8 ) & 0xFF ] ) ^
+ ( (uint32_t) FSb[ ( RK[3] >> 16 ) & 0xFF ] << 8 ) ^
+ ( (uint32_t) FSb[ ( RK[3] >> 24 ) & 0xFF ] << 16 ) ^
+ ( (uint32_t) 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) FSb[ ( RK[5] >> 8 ) & 0xFF ] ) ^
+ ( (uint32_t) FSb[ ( RK[5] >> 16 ) & 0xFF ] << 8 ) ^
+ ( (uint32_t) FSb[ ( RK[5] >> 24 ) & 0xFF ] << 16 ) ^
+ ( (uint32_t) 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) FSb[ ( RK[7] >> 8 ) & 0xFF ] ) ^
+ ( (uint32_t) FSb[ ( RK[7] >> 16 ) & 0xFF ] << 8 ) ^
+ ( (uint32_t) FSb[ ( RK[7] >> 24 ) & 0xFF ] << 16 ) ^
+ ( (uint32_t) 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) FSb[ ( RK[11] ) & 0xFF ] ) ^
+ ( (uint32_t) FSb[ ( RK[11] >> 8 ) & 0xFF ] << 8 ) ^
+ ( (uint32_t) FSb[ ( RK[11] >> 16 ) & 0xFF ] << 16 ) ^
+ ( (uint32_t) 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 /* !MBEDCRYPTO_AES_SETKEY_ENC_ALT */
+
+/*
+ * AES key schedule (decryption)
+ */
+#if !defined(MBEDCRYPTO_AES_SETKEY_DEC_ALT)
+int mbedcrypto_aes_setkey_dec( mbedcrypto_aes_context *ctx, const unsigned char *key,
+ unsigned int keybits )
+{
+ int i, j, ret;
+ mbedcrypto_aes_context cty;
+ uint32_t *RK;
+ uint32_t *SK;
+
+ mbedcrypto_aes_init( &cty );
+
+#if defined(MBEDCRYPTO_PADLOCK_C) && defined(MBEDCRYPTO_PADLOCK_ALIGN16)
+ if( aes_padlock_ace == -1 )
+ aes_padlock_ace = mbedcrypto_padlock_has_support( MBEDCRYPTO_PADLOCK_ACE );
+
+ if( aes_padlock_ace )
+ ctx->rk = RK = MBEDCRYPTO_PADLOCK_ALIGN16( ctx->buf );
+ else
+#endif
+ ctx->rk = RK = ctx->buf;
+
+ /* Also checks keybits */
+ if( ( ret = mbedcrypto_aes_setkey_enc( &cty, key, keybits ) ) != 0 )
+ goto exit;
+
+ ctx->nr = cty.nr;
+
+#if defined(MBEDCRYPTO_AESNI_C) && defined(MBEDCRYPTO_HAVE_X86_64)
+ if( mbedcrypto_aesni_has_support( MBEDCRYPTO_AESNI_AES ) )
+ {
+ mbedcrypto_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++ = AES_RT0( FSb[ ( *SK ) & 0xFF ] ) ^
+ AES_RT1( FSb[ ( *SK >> 8 ) & 0xFF ] ) ^
+ AES_RT2( FSb[ ( *SK >> 16 ) & 0xFF ] ) ^
+ AES_RT3( FSb[ ( *SK >> 24 ) & 0xFF ] );
+ }
+ }
+
+ *RK++ = *SK++;
+ *RK++ = *SK++;
+ *RK++ = *SK++;
+ *RK++ = *SK++;
+
+exit:
+ mbedcrypto_aes_free( &cty );
+
+ return( ret );
+}
+#endif /* !MBEDCRYPTO_AES_SETKEY_DEC_ALT */
+
+#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \
+{ \
+ X0 = *RK++ ^ AES_FT0( ( Y0 ) & 0xFF ) ^ \
+ AES_FT1( ( Y1 >> 8 ) & 0xFF ) ^ \
+ AES_FT2( ( Y2 >> 16 ) & 0xFF ) ^ \
+ AES_FT3( ( Y3 >> 24 ) & 0xFF ); \
+ \
+ X1 = *RK++ ^ AES_FT0( ( Y1 ) & 0xFF ) ^ \
+ AES_FT1( ( Y2 >> 8 ) & 0xFF ) ^ \
+ AES_FT2( ( Y3 >> 16 ) & 0xFF ) ^ \
+ AES_FT3( ( Y0 >> 24 ) & 0xFF ); \
+ \
+ X2 = *RK++ ^ AES_FT0( ( Y2 ) & 0xFF ) ^ \
+ AES_FT1( ( Y3 >> 8 ) & 0xFF ) ^ \
+ AES_FT2( ( Y0 >> 16 ) & 0xFF ) ^ \
+ AES_FT3( ( Y1 >> 24 ) & 0xFF ); \
+ \
+ X3 = *RK++ ^ AES_FT0( ( Y3 ) & 0xFF ) ^ \
+ AES_FT1( ( Y0 >> 8 ) & 0xFF ) ^ \
+ AES_FT2( ( Y1 >> 16 ) & 0xFF ) ^ \
+ AES_FT3( ( Y2 >> 24 ) & 0xFF ); \
+}
+
+#define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \
+{ \
+ X0 = *RK++ ^ AES_RT0( ( Y0 ) & 0xFF ) ^ \
+ AES_RT1( ( Y3 >> 8 ) & 0xFF ) ^ \
+ AES_RT2( ( Y2 >> 16 ) & 0xFF ) ^ \
+ AES_RT3( ( Y1 >> 24 ) & 0xFF ); \
+ \
+ X1 = *RK++ ^ AES_RT0( ( Y1 ) & 0xFF ) ^ \
+ AES_RT1( ( Y0 >> 8 ) & 0xFF ) ^ \
+ AES_RT2( ( Y3 >> 16 ) & 0xFF ) ^ \
+ AES_RT3( ( Y2 >> 24 ) & 0xFF ); \
+ \
+ X2 = *RK++ ^ AES_RT0( ( Y2 ) & 0xFF ) ^ \
+ AES_RT1( ( Y1 >> 8 ) & 0xFF ) ^ \
+ AES_RT2( ( Y0 >> 16 ) & 0xFF ) ^ \
+ AES_RT3( ( Y3 >> 24 ) & 0xFF ); \
+ \
+ X3 = *RK++ ^ AES_RT0( ( Y3 ) & 0xFF ) ^ \
+ AES_RT1( ( Y2 >> 8 ) & 0xFF ) ^ \
+ AES_RT2( ( Y1 >> 16 ) & 0xFF ) ^ \
+ AES_RT3( ( Y0 >> 24 ) & 0xFF ); \
+}
+
+/*
+ * AES-ECB block encryption
+ */
+#if !defined(MBEDCRYPTO_AES_ENCRYPT_ALT)
+int mbedcrypto_internal_aes_encrypt( mbedcrypto_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) FSb[ ( Y0 ) & 0xFF ] ) ^
+ ( (uint32_t) FSb[ ( Y1 >> 8 ) & 0xFF ] << 8 ) ^
+ ( (uint32_t) FSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^
+ ( (uint32_t) FSb[ ( Y3 >> 24 ) & 0xFF ] << 24 );
+
+ X1 = *RK++ ^ \
+ ( (uint32_t) FSb[ ( Y1 ) & 0xFF ] ) ^
+ ( (uint32_t) FSb[ ( Y2 >> 8 ) & 0xFF ] << 8 ) ^
+ ( (uint32_t) FSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^
+ ( (uint32_t) FSb[ ( Y0 >> 24 ) & 0xFF ] << 24 );
+
+ X2 = *RK++ ^ \
+ ( (uint32_t) FSb[ ( Y2 ) & 0xFF ] ) ^
+ ( (uint32_t) FSb[ ( Y3 >> 8 ) & 0xFF ] << 8 ) ^
+ ( (uint32_t) FSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^
+ ( (uint32_t) FSb[ ( Y1 >> 24 ) & 0xFF ] << 24 );
+
+ X3 = *RK++ ^ \
+ ( (uint32_t) FSb[ ( Y3 ) & 0xFF ] ) ^
+ ( (uint32_t) FSb[ ( Y0 >> 8 ) & 0xFF ] << 8 ) ^
+ ( (uint32_t) FSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^
+ ( (uint32_t) 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 );
+
+ return( 0 );
+}
+#endif /* !MBEDCRYPTO_AES_ENCRYPT_ALT */
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_aes_encrypt( mbedcrypto_aes_context *ctx,
+ const unsigned char input[16],
+ unsigned char output[16] )
+{
+ mbedcrypto_internal_aes_encrypt( ctx, input, output );
+}
+#endif /* !MBEDCRYPTO_DEPRECATED_REMOVED */
+
+/*
+ * AES-ECB block decryption
+ */
+#if !defined(MBEDCRYPTO_AES_DECRYPT_ALT)
+int mbedcrypto_internal_aes_decrypt( mbedcrypto_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) RSb[ ( Y0 ) & 0xFF ] ) ^
+ ( (uint32_t) RSb[ ( Y3 >> 8 ) & 0xFF ] << 8 ) ^
+ ( (uint32_t) RSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^
+ ( (uint32_t) RSb[ ( Y1 >> 24 ) & 0xFF ] << 24 );
+
+ X1 = *RK++ ^ \
+ ( (uint32_t) RSb[ ( Y1 ) & 0xFF ] ) ^
+ ( (uint32_t) RSb[ ( Y0 >> 8 ) & 0xFF ] << 8 ) ^
+ ( (uint32_t) RSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^
+ ( (uint32_t) RSb[ ( Y2 >> 24 ) & 0xFF ] << 24 );
+
+ X2 = *RK++ ^ \
+ ( (uint32_t) RSb[ ( Y2 ) & 0xFF ] ) ^
+ ( (uint32_t) RSb[ ( Y1 >> 8 ) & 0xFF ] << 8 ) ^
+ ( (uint32_t) RSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^
+ ( (uint32_t) RSb[ ( Y3 >> 24 ) & 0xFF ] << 24 );
+
+ X3 = *RK++ ^ \
+ ( (uint32_t) RSb[ ( Y3 ) & 0xFF ] ) ^
+ ( (uint32_t) RSb[ ( Y2 >> 8 ) & 0xFF ] << 8 ) ^
+ ( (uint32_t) RSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^
+ ( (uint32_t) 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 );
+
+ return( 0 );
+}
+#endif /* !MBEDCRYPTO_AES_DECRYPT_ALT */
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_aes_decrypt( mbedcrypto_aes_context *ctx,
+ const unsigned char input[16],
+ unsigned char output[16] )
+{
+ mbedcrypto_internal_aes_decrypt( ctx, input, output );
+}
+#endif /* !MBEDCRYPTO_DEPRECATED_REMOVED */
+
+/*
+ * AES-ECB block encryption/decryption
+ */
+int mbedcrypto_aes_crypt_ecb( mbedcrypto_aes_context *ctx,
+ int mode,
+ const unsigned char input[16],
+ unsigned char output[16] )
+{
+#if defined(MBEDCRYPTO_AESNI_C) && defined(MBEDCRYPTO_HAVE_X86_64)
+ if( mbedcrypto_aesni_has_support( MBEDCRYPTO_AESNI_AES ) )
+ return( mbedcrypto_aesni_crypt_ecb( ctx, mode, input, output ) );
+#endif
+
+#if defined(MBEDCRYPTO_PADLOCK_C) && defined(MBEDCRYPTO_HAVE_X86)
+ if( aes_padlock_ace )
+ {
+ if( mbedcrypto_padlock_xcryptecb( ctx, mode, input, output ) == 0 )
+ return( 0 );
+
+ // If padlock data misaligned, we just fall back to
+ // unaccelerated mode
+ //
+ }
+#endif
+
+ if( mode == MBEDCRYPTO_AES_ENCRYPT )
+ return( mbedcrypto_internal_aes_encrypt( ctx, input, output ) );
+ else
+ return( mbedcrypto_internal_aes_decrypt( ctx, input, output ) );
+}
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+/*
+ * AES-CBC buffer encryption/decryption
+ */
+int mbedcrypto_aes_crypt_cbc( mbedcrypto_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( MBEDCRYPTO_ERR_AES_INVALID_INPUT_LENGTH );
+
+#if defined(MBEDCRYPTO_PADLOCK_C) && defined(MBEDCRYPTO_HAVE_X86)
+ if( aes_padlock_ace )
+ {
+ if( mbedcrypto_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 == MBEDCRYPTO_AES_DECRYPT )
+ {
+ while( length > 0 )
+ {
+ memcpy( temp, input, 16 );
+ mbedcrypto_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] );
+
+ mbedcrypto_aes_crypt_ecb( ctx, mode, output, output );
+ memcpy( iv, output, 16 );
+
+ input += 16;
+ output += 16;
+ length -= 16;
+ }
+ }
+
+ return( 0 );
+}
+#endif /* MBEDCRYPTO_CIPHER_MODE_CBC */
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CFB)
+/*
+ * AES-CFB128 buffer encryption/decryption
+ */
+int mbedcrypto_aes_crypt_cfb128( mbedcrypto_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 == MBEDCRYPTO_AES_DECRYPT )
+ {
+ while( length-- )
+ {
+ if( n == 0 )
+ mbedcrypto_aes_crypt_ecb( ctx, MBEDCRYPTO_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 )
+ mbedcrypto_aes_crypt_ecb( ctx, MBEDCRYPTO_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 mbedcrypto_aes_crypt_cfb8( mbedcrypto_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 );
+ mbedcrypto_aes_crypt_ecb( ctx, MBEDCRYPTO_AES_ENCRYPT, iv, iv );
+
+ if( mode == MBEDCRYPTO_AES_DECRYPT )
+ ov[16] = *input;
+
+ c = *output++ = (unsigned char)( iv[0] ^ *input++ );
+
+ if( mode == MBEDCRYPTO_AES_ENCRYPT )
+ ov[16] = c;
+
+ memcpy( iv, ov + 1, 16 );
+ }
+
+ return( 0 );
+}
+#endif /*MBEDCRYPTO_CIPHER_MODE_CFB */
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CTR)
+/*
+ * AES-CTR buffer encryption/decryption
+ */
+int mbedcrypto_aes_crypt_ctr( mbedcrypto_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 ) {
+ mbedcrypto_aes_crypt_ecb( ctx, MBEDCRYPTO_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 /* MBEDCRYPTO_CIPHER_MODE_CTR */
+
+#endif /* !MBEDCRYPTO_AES_ALT */
+
+#if defined(MBEDCRYPTO_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(MBEDCRYPTO_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 /* MBEDCRYPTO_CIPHER_MODE_CBC */
+
+#if defined(MBEDCRYPTO_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 /* MBEDCRYPTO_CIPHER_MODE_CFB */
+
+#if defined(MBEDCRYPTO_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 /* MBEDCRYPTO_CIPHER_MODE_CTR */
+
+/*
+ * Checkup routine
+ */
+int mbedcrypto_aes_self_test( int verbose )
+{
+ int ret = 0, i, j, u, mode;
+ unsigned int keybits;
+ unsigned char key[32];
+ unsigned char buf[64];
+ const unsigned char *aes_tests;
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC) || defined(MBEDCRYPTO_CIPHER_MODE_CFB)
+ unsigned char iv[16];
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+ unsigned char prv[16];
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CTR) || defined(MBEDCRYPTO_CIPHER_MODE_CFB)
+ size_t offset;
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CTR)
+ int len;
+ unsigned char nonce_counter[16];
+ unsigned char stream_block[16];
+#endif
+ mbedcrypto_aes_context ctx;
+
+ memset( key, 0, 32 );
+ mbedcrypto_aes_init( &ctx );
+
+ /*
+ * ECB mode
+ */
+ for( i = 0; i < 6; i++ )
+ {
+ u = i >> 1;
+ keybits = 128 + u * 64;
+ mode = i & 1;
+
+ if( verbose != 0 )
+ mbedcrypto_printf( " AES-ECB-%3d (%s): ", keybits,
+ ( mode == MBEDCRYPTO_AES_DECRYPT ) ? "dec" : "enc" );
+
+ memset( buf, 0, 16 );
+
+ if( mode == MBEDCRYPTO_AES_DECRYPT )
+ {
+ ret = mbedcrypto_aes_setkey_dec( &ctx, key, keybits );
+ aes_tests = aes_test_ecb_dec[u];
+ }
+ else
+ {
+ ret = mbedcrypto_aes_setkey_enc( &ctx, key, keybits );
+ aes_tests = aes_test_ecb_enc[u];
+ }
+
+ /*
+ * AES-192 is an optional feature that may be unavailable when
+ * there is an alternative underlying implementation i.e. when
+ * MBEDCRYPTO_AES_ALT is defined.
+ */
+ if( ret == MBEDCRYPTO_ERR_AES_FEATURE_UNAVAILABLE && keybits == 192 )
+ {
+ mbedcrypto_printf( "skipped\n" );
+ continue;
+ }
+ else if( ret != 0 )
+ {
+ goto exit;
+ }
+
+ for( j = 0; j < 10000; j++ )
+ {
+ ret = mbedcrypto_aes_crypt_ecb( &ctx, mode, buf, buf );
+ if( ret != 0 )
+ goto exit;
+ }
+
+ if( memcmp( buf, aes_tests, 16 ) != 0 )
+ {
+ ret = 1;
+ goto exit;
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "\n" );
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+ /*
+ * CBC mode
+ */
+ for( i = 0; i < 6; i++ )
+ {
+ u = i >> 1;
+ keybits = 128 + u * 64;
+ mode = i & 1;
+
+ if( verbose != 0 )
+ mbedcrypto_printf( " AES-CBC-%3d (%s): ", keybits,
+ ( mode == MBEDCRYPTO_AES_DECRYPT ) ? "dec" : "enc" );
+
+ memset( iv , 0, 16 );
+ memset( prv, 0, 16 );
+ memset( buf, 0, 16 );
+
+ if( mode == MBEDCRYPTO_AES_DECRYPT )
+ {
+ ret = mbedcrypto_aes_setkey_dec( &ctx, key, keybits );
+ aes_tests = aes_test_cbc_dec[u];
+ }
+ else
+ {
+ ret = mbedcrypto_aes_setkey_enc( &ctx, key, keybits );
+ aes_tests = aes_test_cbc_enc[u];
+ }
+
+ /*
+ * AES-192 is an optional feature that may be unavailable when
+ * there is an alternative underlying implementation i.e. when
+ * MBEDCRYPTO_AES_ALT is defined.
+ */
+ if( ret == MBEDCRYPTO_ERR_AES_FEATURE_UNAVAILABLE && keybits == 192 )
+ {
+ mbedcrypto_printf( "skipped\n" );
+ continue;
+ }
+ else if( ret != 0 )
+ {
+ goto exit;
+ }
+
+ for( j = 0; j < 10000; j++ )
+ {
+ if( mode == MBEDCRYPTO_AES_ENCRYPT )
+ {
+ unsigned char tmp[16];
+
+ memcpy( tmp, prv, 16 );
+ memcpy( prv, buf, 16 );
+ memcpy( buf, tmp, 16 );
+ }
+
+ ret = mbedcrypto_aes_crypt_cbc( &ctx, mode, 16, iv, buf, buf );
+ if( ret != 0 )
+ goto exit;
+
+ }
+
+ if( memcmp( buf, aes_tests, 16 ) != 0 )
+ {
+ ret = 1;
+ goto exit;
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "\n" );
+#endif /* MBEDCRYPTO_CIPHER_MODE_CBC */
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CFB)
+ /*
+ * CFB128 mode
+ */
+ for( i = 0; i < 6; i++ )
+ {
+ u = i >> 1;
+ keybits = 128 + u * 64;
+ mode = i & 1;
+
+ if( verbose != 0 )
+ mbedcrypto_printf( " AES-CFB128-%3d (%s): ", keybits,
+ ( mode == MBEDCRYPTO_AES_DECRYPT ) ? "dec" : "enc" );
+
+ memcpy( iv, aes_test_cfb128_iv, 16 );
+ memcpy( key, aes_test_cfb128_key[u], keybits / 8 );
+
+ offset = 0;
+ ret = mbedcrypto_aes_setkey_enc( &ctx, key, keybits );
+ /*
+ * AES-192 is an optional feature that may be unavailable when
+ * there is an alternative underlying implementation i.e. when
+ * MBEDCRYPTO_AES_ALT is defined.
+ */
+ if( ret == MBEDCRYPTO_ERR_AES_FEATURE_UNAVAILABLE && keybits == 192 )
+ {
+ mbedcrypto_printf( "skipped\n" );
+ continue;
+ }
+ else if( ret != 0 )
+ {
+ goto exit;
+ }
+
+ if( mode == MBEDCRYPTO_AES_DECRYPT )
+ {
+ memcpy( buf, aes_test_cfb128_ct[u], 64 );
+ aes_tests = aes_test_cfb128_pt;
+ }
+ else
+ {
+ memcpy( buf, aes_test_cfb128_pt, 64 );
+ aes_tests = aes_test_cfb128_ct[u];
+ }
+
+ ret = mbedcrypto_aes_crypt_cfb128( &ctx, mode, 64, &offset, iv, buf, buf );
+ if( ret != 0 )
+ goto exit;
+
+ if( memcmp( buf, aes_tests, 64 ) != 0 )
+ {
+ ret = 1;
+ goto exit;
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "\n" );
+#endif /* MBEDCRYPTO_CIPHER_MODE_CFB */
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CTR)
+ /*
+ * CTR mode
+ */
+ for( i = 0; i < 6; i++ )
+ {
+ u = i >> 1;
+ mode = i & 1;
+
+ if( verbose != 0 )
+ mbedcrypto_printf( " AES-CTR-128 (%s): ",
+ ( mode == MBEDCRYPTO_AES_DECRYPT ) ? "dec" : "enc" );
+
+ memcpy( nonce_counter, aes_test_ctr_nonce_counter[u], 16 );
+ memcpy( key, aes_test_ctr_key[u], 16 );
+
+ offset = 0;
+ if( ( ret = mbedcrypto_aes_setkey_enc( &ctx, key, 128 ) ) != 0 )
+ goto exit;
+
+ len = aes_test_ctr_len[u];
+
+ if( mode == MBEDCRYPTO_AES_DECRYPT )
+ {
+ memcpy( buf, aes_test_ctr_ct[u], len );
+ aes_tests = aes_test_ctr_pt[u];
+ }
+ else
+ {
+ memcpy( buf, aes_test_ctr_pt[u], len );
+ aes_tests = aes_test_ctr_ct[u];
+ }
+
+ ret = mbedcrypto_aes_crypt_ctr( &ctx, len, &offset, nonce_counter,
+ stream_block, buf, buf );
+ if( ret != 0 )
+ goto exit;
+
+ if( memcmp( buf, aes_tests, len ) != 0 )
+ {
+ ret = 1;
+ goto exit;
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "\n" );
+#endif /* MBEDCRYPTO_CIPHER_MODE_CTR */
+
+ ret = 0;
+
+exit:
+ if( ret != 0 && verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+
+ mbedcrypto_aes_free( &ctx );
+
+ return( ret );
+}
+
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#endif /* MBEDCRYPTO_AES_C */
diff --git a/library/aesni.c b/library/aesni.c
new file mode 100644
index 0000000..5a3ea2d
--- /dev/null
+++ b/library/aesni.c
@@ -0,0 +1,470 @@
+/*
+ * 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 Crypto (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(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_AESNI_C)
+
+#if defined(__has_feature)
+#if __has_feature(memory_sanitizer)
+#warning "MBEDCRYPTO_AESNI_C is known to cause spurious error reports with some memory sanitizers as they do not understand the assembly code."
+#endif
+#endif
+
+#include "mbedcrypto/aesni.h"
+
+#include <string.h>
+
+#ifndef asm
+#define asm __asm
+#endif
+
+#if defined(MBEDCRYPTO_HAVE_X86_64)
+
+/*
+ * AES-NI support detection routine
+ */
+int mbedcrypto_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 mbedcrypto_aesni_crypt_ecb( mbedcrypto_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
+ "add $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
+ "add $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
+ "add $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 mbedcrypto_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 mbedcrypto_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 mbedcrypto_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 mbedcrypto_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( MBEDCRYPTO_ERR_AES_INVALID_KEY_LENGTH );
+ }
+
+ return( 0 );
+}
+
+#endif /* MBEDCRYPTO_HAVE_X86_64 */
+
+#endif /* MBEDCRYPTO_AESNI_C */
diff --git a/library/arc4.c b/library/arc4.c
new file mode 100644
index 0000000..9ee6dc1
--- /dev/null
+++ b/library/arc4.c
@@ -0,0 +1,201 @@
+/*
+ * 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 Crypto (https://tls.mbed.org)
+ */
+/*
+ * The ARCFOUR algorithm was publicly disclosed on 94/09.
+ *
+ * http://groups.google.com/group/sci.crypt/msg/10a300c9d21afca0
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_ARC4_C)
+
+#include "mbedcrypto/arc4.h"
+#include "mbedcrypto/platform_util.h"
+
+#include <string.h>
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#include <stdio.h>
+#define mbedcrypto_printf printf
+#endif /* MBEDCRYPTO_PLATFORM_C */
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#if !defined(MBEDCRYPTO_ARC4_ALT)
+
+void mbedcrypto_arc4_init( mbedcrypto_arc4_context *ctx )
+{
+ memset( ctx, 0, sizeof( mbedcrypto_arc4_context ) );
+}
+
+void mbedcrypto_arc4_free( mbedcrypto_arc4_context *ctx )
+{
+ if( ctx == NULL )
+ return;
+
+ mbedcrypto_platform_zeroize( ctx, sizeof( mbedcrypto_arc4_context ) );
+}
+
+/*
+ * ARC4 key schedule
+ */
+void mbedcrypto_arc4_setup( mbedcrypto_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 mbedcrypto_arc4_crypt( mbedcrypto_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 /* !MBEDCRYPTO_ARC4_ALT */
+
+#if defined(MBEDCRYPTO_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 mbedcrypto_arc4_self_test( int verbose )
+{
+ int i, ret = 0;
+ unsigned char ibuf[8];
+ unsigned char obuf[8];
+ mbedcrypto_arc4_context ctx;
+
+ mbedcrypto_arc4_init( &ctx );
+
+ for( i = 0; i < 3; i++ )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( " ARC4 test #%d: ", i + 1 );
+
+ memcpy( ibuf, arc4_test_pt[i], 8 );
+
+ mbedcrypto_arc4_setup( &ctx, arc4_test_key[i], 8 );
+ mbedcrypto_arc4_crypt( &ctx, 8, ibuf, obuf );
+
+ if( memcmp( obuf, arc4_test_ct[i], 8 ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+
+ ret = 1;
+ goto exit;
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "\n" );
+
+exit:
+ mbedcrypto_arc4_free( &ctx );
+
+ return( ret );
+}
+
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#endif /* MBEDCRYPTO_ARC4_C */
diff --git a/library/asn1parse.c b/library/asn1parse.c
new file mode 100644
index 0000000..1375614
--- /dev/null
+++ b/library/asn1parse.c
@@ -0,0 +1,389 @@
+/*
+ * 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 Crypto (https://tls.mbed.org)
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_ASN1_PARSE_C)
+
+#include "mbedcrypto/asn1.h"
+#include "mbedcrypto/platform_util.h"
+
+#include <string.h>
+
+#if defined(MBEDCRYPTO_BIGNUM_C)
+#include "mbedcrypto/bignum.h"
+#endif
+
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#include <stdlib.h>
+#define mbedcrypto_calloc calloc
+#define mbedcrypto_free free
+#endif
+
+/*
+ * ASN.1 DER decoding routines
+ */
+int mbedcrypto_asn1_get_len( unsigned char **p,
+ const unsigned char *end,
+ size_t *len )
+{
+ if( ( end - *p ) < 1 )
+ return( MBEDCRYPTO_ERR_ASN1_OUT_OF_DATA );
+
+ if( ( **p & 0x80 ) == 0 )
+ *len = *(*p)++;
+ else
+ {
+ switch( **p & 0x7F )
+ {
+ case 1:
+ if( ( end - *p ) < 2 )
+ return( MBEDCRYPTO_ERR_ASN1_OUT_OF_DATA );
+
+ *len = (*p)[1];
+ (*p) += 2;
+ break;
+
+ case 2:
+ if( ( end - *p ) < 3 )
+ return( MBEDCRYPTO_ERR_ASN1_OUT_OF_DATA );
+
+ *len = ( (size_t)(*p)[1] << 8 ) | (*p)[2];
+ (*p) += 3;
+ break;
+
+ case 3:
+ if( ( end - *p ) < 4 )
+ return( MBEDCRYPTO_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( MBEDCRYPTO_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( MBEDCRYPTO_ERR_ASN1_INVALID_LENGTH );
+ }
+ }
+
+ if( *len > (size_t) ( end - *p ) )
+ return( MBEDCRYPTO_ERR_ASN1_OUT_OF_DATA );
+
+ return( 0 );
+}
+
+int mbedcrypto_asn1_get_tag( unsigned char **p,
+ const unsigned char *end,
+ size_t *len, int tag )
+{
+ if( ( end - *p ) < 1 )
+ return( MBEDCRYPTO_ERR_ASN1_OUT_OF_DATA );
+
+ if( **p != tag )
+ return( MBEDCRYPTO_ERR_ASN1_UNEXPECTED_TAG );
+
+ (*p)++;
+
+ return( mbedcrypto_asn1_get_len( p, end, len ) );
+}
+
+int mbedcrypto_asn1_get_bool( unsigned char **p,
+ const unsigned char *end,
+ int *val )
+{
+ int ret;
+ size_t len;
+
+ if( ( ret = mbedcrypto_asn1_get_tag( p, end, &len, MBEDCRYPTO_ASN1_BOOLEAN ) ) != 0 )
+ return( ret );
+
+ if( len != 1 )
+ return( MBEDCRYPTO_ERR_ASN1_INVALID_LENGTH );
+
+ *val = ( **p != 0 ) ? 1 : 0;
+ (*p)++;
+
+ return( 0 );
+}
+
+int mbedcrypto_asn1_get_int( unsigned char **p,
+ const unsigned char *end,
+ int *val )
+{
+ int ret;
+ size_t len;
+
+ if( ( ret = mbedcrypto_asn1_get_tag( p, end, &len, MBEDCRYPTO_ASN1_INTEGER ) ) != 0 )
+ return( ret );
+
+ if( len == 0 || len > sizeof( int ) || ( **p & 0x80 ) != 0 )
+ return( MBEDCRYPTO_ERR_ASN1_INVALID_LENGTH );
+
+ *val = 0;
+
+ while( len-- > 0 )
+ {
+ *val = ( *val << 8 ) | **p;
+ (*p)++;
+ }
+
+ return( 0 );
+}
+
+#if defined(MBEDCRYPTO_BIGNUM_C)
+int mbedcrypto_asn1_get_mpi( unsigned char **p,
+ const unsigned char *end,
+ mbedcrypto_mpi *X )
+{
+ int ret;
+ size_t len;
+
+ if( ( ret = mbedcrypto_asn1_get_tag( p, end, &len, MBEDCRYPTO_ASN1_INTEGER ) ) != 0 )
+ return( ret );
+
+ ret = mbedcrypto_mpi_read_binary( X, *p, len );
+
+ *p += len;
+
+ return( ret );
+}
+#endif /* MBEDCRYPTO_BIGNUM_C */
+
+int mbedcrypto_asn1_get_bitstring( unsigned char **p, const unsigned char *end,
+ mbedcrypto_asn1_bitstring *bs)
+{
+ int ret;
+
+ /* Certificate type is a single byte bitstring */
+ if( ( ret = mbedcrypto_asn1_get_tag( p, end, &bs->len, MBEDCRYPTO_ASN1_BIT_STRING ) ) != 0 )
+ return( ret );
+
+ /* Check length, subtract one for actual bit string length */
+ if( bs->len < 1 )
+ return( MBEDCRYPTO_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( MBEDCRYPTO_ERR_ASN1_INVALID_LENGTH );
+ (*p)++;
+
+ /* Get actual bitstring */
+ bs->p = *p;
+ *p += bs->len;
+
+ if( *p != end )
+ return( MBEDCRYPTO_ERR_ASN1_LENGTH_MISMATCH );
+
+ return( 0 );
+}
+
+/*
+ * Get a bit string without unused bits
+ */
+int mbedcrypto_asn1_get_bitstring_null( unsigned char **p, const unsigned char *end,
+ size_t *len )
+{
+ int ret;
+
+ if( ( ret = mbedcrypto_asn1_get_tag( p, end, len, MBEDCRYPTO_ASN1_BIT_STRING ) ) != 0 )
+ return( ret );
+
+ if( (*len)-- < 2 || *(*p)++ != 0 )
+ return( MBEDCRYPTO_ERR_ASN1_INVALID_DATA );
+
+ return( 0 );
+}
+
+
+
+/*
+ * Parses and splits an ASN.1 "SEQUENCE OF <tag>"
+ */
+int mbedcrypto_asn1_get_sequence_of( unsigned char **p,
+ const unsigned char *end,
+ mbedcrypto_asn1_sequence *cur,
+ int tag)
+{
+ int ret;
+ size_t len;
+ mbedcrypto_asn1_buf *buf;
+
+ /* Get main sequence tag */
+ if( ( ret = mbedcrypto_asn1_get_tag( p, end, &len,
+ MBEDCRYPTO_ASN1_CONSTRUCTED | MBEDCRYPTO_ASN1_SEQUENCE ) ) != 0 )
+ return( ret );
+
+ if( *p + len != end )
+ return( MBEDCRYPTO_ERR_ASN1_LENGTH_MISMATCH );
+
+ while( *p < end )
+ {
+ buf = &(cur->buf);
+ buf->tag = **p;
+
+ if( ( ret = mbedcrypto_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 = (mbedcrypto_asn1_sequence*)mbedcrypto_calloc( 1,
+ sizeof( mbedcrypto_asn1_sequence ) );
+
+ if( cur->next == NULL )
+ return( MBEDCRYPTO_ERR_ASN1_ALLOC_FAILED );
+
+ cur = cur->next;
+ }
+ }
+
+ /* Set final sequence entry's next pointer to NULL */
+ cur->next = NULL;
+
+ if( *p != end )
+ return( MBEDCRYPTO_ERR_ASN1_LENGTH_MISMATCH );
+
+ return( 0 );
+}
+
+int mbedcrypto_asn1_get_alg( unsigned char **p,
+ const unsigned char *end,
+ mbedcrypto_asn1_buf *alg, mbedcrypto_asn1_buf *params )
+{
+ int ret;
+ size_t len;
+
+ if( ( ret = mbedcrypto_asn1_get_tag( p, end, &len,
+ MBEDCRYPTO_ASN1_CONSTRUCTED | MBEDCRYPTO_ASN1_SEQUENCE ) ) != 0 )
+ return( ret );
+
+ if( ( end - *p ) < 1 )
+ return( MBEDCRYPTO_ERR_ASN1_OUT_OF_DATA );
+
+ alg->tag = **p;
+ end = *p + len;
+
+ if( ( ret = mbedcrypto_asn1_get_tag( p, end, &alg->len, MBEDCRYPTO_ASN1_OID ) ) != 0 )
+ return( ret );
+
+ alg->p = *p;
+ *p += alg->len;
+
+ if( *p == end )
+ {
+ mbedcrypto_platform_zeroize( params, sizeof(mbedcrypto_asn1_buf) );
+ return( 0 );
+ }
+
+ params->tag = **p;
+ (*p)++;
+
+ if( ( ret = mbedcrypto_asn1_get_len( p, end, ¶ms->len ) ) != 0 )
+ return( ret );
+
+ params->p = *p;
+ *p += params->len;
+
+ if( *p != end )
+ return( MBEDCRYPTO_ERR_ASN1_LENGTH_MISMATCH );
+
+ return( 0 );
+}
+
+int mbedcrypto_asn1_get_alg_null( unsigned char **p,
+ const unsigned char *end,
+ mbedcrypto_asn1_buf *alg )
+{
+ int ret;
+ mbedcrypto_asn1_buf params;
+
+ memset( ¶ms, 0, sizeof(mbedcrypto_asn1_buf) );
+
+ if( ( ret = mbedcrypto_asn1_get_alg( p, end, alg, ¶ms ) ) != 0 )
+ return( ret );
+
+ if( ( params.tag != MBEDCRYPTO_ASN1_NULL && params.tag != 0 ) || params.len != 0 )
+ return( MBEDCRYPTO_ERR_ASN1_INVALID_DATA );
+
+ return( 0 );
+}
+
+void mbedcrypto_asn1_free_named_data( mbedcrypto_asn1_named_data *cur )
+{
+ if( cur == NULL )
+ return;
+
+ mbedcrypto_free( cur->oid.p );
+ mbedcrypto_free( cur->val.p );
+
+ mbedcrypto_platform_zeroize( cur, sizeof( mbedcrypto_asn1_named_data ) );
+}
+
+void mbedcrypto_asn1_free_named_data_list( mbedcrypto_asn1_named_data **head )
+{
+ mbedcrypto_asn1_named_data *cur;
+
+ while( ( cur = *head ) != NULL )
+ {
+ *head = cur->next;
+ mbedcrypto_asn1_free_named_data( cur );
+ mbedcrypto_free( cur );
+ }
+}
+
+mbedcrypto_asn1_named_data *mbedcrypto_asn1_find_named_data( mbedcrypto_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 /* MBEDCRYPTO_ASN1_PARSE_C */
diff --git a/library/asn1write.c b/library/asn1write.c
new file mode 100644
index 0000000..87c5ef6
--- /dev/null
+++ b/library/asn1write.c
@@ -0,0 +1,386 @@
+/*
+ * 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 Crypto (https://tls.mbed.org)
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_ASN1_WRITE_C)
+
+#include "mbedcrypto/asn1write.h"
+
+#include <string.h>
+
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#include <stdlib.h>
+#define mbedcrypto_calloc calloc
+#define mbedcrypto_free free
+#endif
+
+int mbedcrypto_asn1_write_len( unsigned char **p, unsigned char *start, size_t len )
+{
+ if( len < 0x80 )
+ {
+ if( *p - start < 1 )
+ return( MBEDCRYPTO_ERR_ASN1_BUF_TOO_SMALL );
+
+ *--(*p) = (unsigned char) len;
+ return( 1 );
+ }
+
+ if( len <= 0xFF )
+ {
+ if( *p - start < 2 )
+ return( MBEDCRYPTO_ERR_ASN1_BUF_TOO_SMALL );
+
+ *--(*p) = (unsigned char) len;
+ *--(*p) = 0x81;
+ return( 2 );
+ }
+
+ if( len <= 0xFFFF )
+ {
+ if( *p - start < 3 )
+ return( MBEDCRYPTO_ERR_ASN1_BUF_TOO_SMALL );
+
+ *--(*p) = ( len ) & 0xFF;
+ *--(*p) = ( len >> 8 ) & 0xFF;
+ *--(*p) = 0x82;
+ return( 3 );
+ }
+
+ if( len <= 0xFFFFFF )
+ {
+ if( *p - start < 4 )
+ return( MBEDCRYPTO_ERR_ASN1_BUF_TOO_SMALL );
+
+ *--(*p) = ( len ) & 0xFF;
+ *--(*p) = ( len >> 8 ) & 0xFF;
+ *--(*p) = ( len >> 16 ) & 0xFF;
+ *--(*p) = 0x83;
+ return( 4 );
+ }
+
+ if( len <= 0xFFFFFFFF )
+ {
+ if( *p - start < 5 )
+ return( MBEDCRYPTO_ERR_ASN1_BUF_TOO_SMALL );
+
+ *--(*p) = ( len ) & 0xFF;
+ *--(*p) = ( len >> 8 ) & 0xFF;
+ *--(*p) = ( len >> 16 ) & 0xFF;
+ *--(*p) = ( len >> 24 ) & 0xFF;
+ *--(*p) = 0x84;
+ return( 5 );
+ }
+
+ return( MBEDCRYPTO_ERR_ASN1_INVALID_LENGTH );
+}
+
+int mbedcrypto_asn1_write_tag( unsigned char **p, unsigned char *start, unsigned char tag )
+{
+ if( *p - start < 1 )
+ return( MBEDCRYPTO_ERR_ASN1_BUF_TOO_SMALL );
+
+ *--(*p) = tag;
+
+ return( 1 );
+}
+
+int mbedcrypto_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( MBEDCRYPTO_ERR_ASN1_BUF_TOO_SMALL );
+
+ len = size;
+ (*p) -= len;
+ memcpy( *p, buf, len );
+
+ return( (int) len );
+}
+
+#if defined(MBEDCRYPTO_BIGNUM_C)
+int mbedcrypto_asn1_write_mpi( unsigned char **p, unsigned char *start, const mbedcrypto_mpi *X )
+{
+ int ret;
+ size_t len = 0;
+
+ // Write the MPI
+ //
+ len = mbedcrypto_mpi_size( X );
+
+ if( *p < start || (size_t)( *p - start ) < len )
+ return( MBEDCRYPTO_ERR_ASN1_BUF_TOO_SMALL );
+
+ (*p) -= len;
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_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( MBEDCRYPTO_ERR_ASN1_BUF_TOO_SMALL );
+
+ *--(*p) = 0x00;
+ len += 1;
+ }
+
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_len( p, start, len ) );
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_tag( p, start, MBEDCRYPTO_ASN1_INTEGER ) );
+
+ ret = (int) len;
+
+cleanup:
+ return( ret );
+}
+#endif /* MBEDCRYPTO_BIGNUM_C */
+
+int mbedcrypto_asn1_write_null( unsigned char **p, unsigned char *start )
+{
+ int ret;
+ size_t len = 0;
+
+ // Write NULL
+ //
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_len( p, start, 0) );
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_tag( p, start, MBEDCRYPTO_ASN1_NULL ) );
+
+ return( (int) len );
+}
+
+int mbedcrypto_asn1_write_oid( unsigned char **p, unsigned char *start,
+ const char *oid, size_t oid_len )
+{
+ int ret;
+ size_t len = 0;
+
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_raw_buffer( p, start,
+ (const unsigned char *) oid, oid_len ) );
+ MBEDCRYPTO_ASN1_CHK_ADD( len , mbedcrypto_asn1_write_len( p, start, len ) );
+ MBEDCRYPTO_ASN1_CHK_ADD( len , mbedcrypto_asn1_write_tag( p, start, MBEDCRYPTO_ASN1_OID ) );
+
+ return( (int) len );
+}
+
+int mbedcrypto_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 )
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_null( p, start ) );
+ else
+ len += par_len;
+
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_oid( p, start, oid, oid_len ) );
+
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_len( p, start, len ) );
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_tag( p, start,
+ MBEDCRYPTO_ASN1_CONSTRUCTED | MBEDCRYPTO_ASN1_SEQUENCE ) );
+
+ return( (int) len );
+}
+
+int mbedcrypto_asn1_write_bool( unsigned char **p, unsigned char *start, int boolean )
+{
+ int ret;
+ size_t len = 0;
+
+ if( *p - start < 1 )
+ return( MBEDCRYPTO_ERR_ASN1_BUF_TOO_SMALL );
+
+ *--(*p) = (boolean) ? 255 : 0;
+ len++;
+
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_len( p, start, len ) );
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_tag( p, start, MBEDCRYPTO_ASN1_BOOLEAN ) );
+
+ return( (int) len );
+}
+
+int mbedcrypto_asn1_write_int( unsigned char **p, unsigned char *start, int val )
+{
+ int ret;
+ size_t len = 0;
+
+ if( *p - start < 1 )
+ return( MBEDCRYPTO_ERR_ASN1_BUF_TOO_SMALL );
+
+ len += 1;
+ *--(*p) = val;
+
+ if( val > 0 && **p & 0x80 )
+ {
+ if( *p - start < 1 )
+ return( MBEDCRYPTO_ERR_ASN1_BUF_TOO_SMALL );
+
+ *--(*p) = 0x00;
+ len += 1;
+ }
+
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_len( p, start, len ) );
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_tag( p, start, MBEDCRYPTO_ASN1_INTEGER ) );
+
+ return( (int) len );
+}
+
+int mbedcrypto_asn1_write_printable_string( unsigned char **p, unsigned char *start,
+ const char *text, size_t text_len )
+{
+ int ret;
+ size_t len = 0;
+
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_raw_buffer( p, start,
+ (const unsigned char *) text, text_len ) );
+
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_len( p, start, len ) );
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_tag( p, start, MBEDCRYPTO_ASN1_PRINTABLE_STRING ) );
+
+ return( (int) len );
+}
+
+int mbedcrypto_asn1_write_ia5_string( unsigned char **p, unsigned char *start,
+ const char *text, size_t text_len )
+{
+ int ret;
+ size_t len = 0;
+
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_raw_buffer( p, start,
+ (const unsigned char *) text, text_len ) );
+
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_len( p, start, len ) );
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_tag( p, start, MBEDCRYPTO_ASN1_IA5_STRING ) );
+
+ return( (int) len );
+}
+
+int mbedcrypto_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( MBEDCRYPTO_ERR_ASN1_BUF_TOO_SMALL );
+
+ len = size + 1;
+ (*p) -= size;
+ memcpy( *p, buf, size );
+
+ // Write unused bits
+ //
+ *--(*p) = (unsigned char) (size * 8 - bits);
+
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_len( p, start, len ) );
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_tag( p, start, MBEDCRYPTO_ASN1_BIT_STRING ) );
+
+ return( (int) len );
+}
+
+int mbedcrypto_asn1_write_octet_string( unsigned char **p, unsigned char *start,
+ const unsigned char *buf, size_t size )
+{
+ int ret;
+ size_t len = 0;
+
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_raw_buffer( p, start, buf, size ) );
+
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_len( p, start, len ) );
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_tag( p, start, MBEDCRYPTO_ASN1_OCTET_STRING ) );
+
+ return( (int) len );
+}
+
+mbedcrypto_asn1_named_data *mbedcrypto_asn1_store_named_data( mbedcrypto_asn1_named_data **head,
+ const char *oid, size_t oid_len,
+ const unsigned char *val,
+ size_t val_len )
+{
+ mbedcrypto_asn1_named_data *cur;
+
+ if( ( cur = mbedcrypto_asn1_find_named_data( *head, oid, oid_len ) ) == NULL )
+ {
+ // Add new entry if not present yet based on OID
+ //
+ cur = (mbedcrypto_asn1_named_data*)mbedcrypto_calloc( 1,
+ sizeof(mbedcrypto_asn1_named_data) );
+ if( cur == NULL )
+ return( NULL );
+
+ cur->oid.len = oid_len;
+ cur->oid.p = mbedcrypto_calloc( 1, oid_len );
+ if( cur->oid.p == NULL )
+ {
+ mbedcrypto_free( cur );
+ return( NULL );
+ }
+
+ memcpy( cur->oid.p, oid, oid_len );
+
+ cur->val.len = val_len;
+ cur->val.p = mbedcrypto_calloc( 1, val_len );
+ if( cur->val.p == NULL )
+ {
+ mbedcrypto_free( cur->oid.p );
+ mbedcrypto_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 = mbedcrypto_calloc( 1, val_len );
+ if( p == NULL )
+ return( NULL );
+
+ mbedcrypto_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 /* MBEDCRYPTO_ASN1_WRITE_C */
diff --git a/library/base64.c b/library/base64.c
new file mode 100644
index 0000000..637f30b
--- /dev/null
+++ b/library/base64.c
@@ -0,0 +1,293 @@
+/*
+ * 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 Crypto (https://tls.mbed.org)
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_BASE64_C)
+
+#include "mbedcrypto/base64.h"
+
+#include <stdint.h>
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+#include <string.h>
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#include <stdio.h>
+#define mbedcrypto_printf printf
+#endif /* MBEDCRYPTO_PLATFORM_C */
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+static const unsigned char base64_enc_map[64] =
+{
+ '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] =
+{
+ 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 mbedcrypto_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( MBEDCRYPTO_ERR_BASE64_BUFFER_TOO_SMALL );
+ }
+
+ n *= 4;
+
+ if( ( dlen < n + 1 ) || ( NULL == dst ) )
+ {
+ *olen = n + 1;
+ return( MBEDCRYPTO_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++ = base64_enc_map[(C1 >> 2) & 0x3F];
+ *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
+ *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
+ *p++ = base64_enc_map[C3 & 0x3F];
+ }
+
+ if( i < slen )
+ {
+ C1 = *src++;
+ C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
+
+ *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
+ *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
+
+ if( ( i + 1 ) < slen )
+ *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
+ else *p++ = '=';
+
+ *p++ = '=';
+ }
+
+ *olen = p - dst;
+ *p = 0;
+
+ return( 0 );
+}
+
+/*
+ * Decode a base64-formatted buffer
+ */
+int mbedcrypto_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( MBEDCRYPTO_ERR_BASE64_INVALID_CHARACTER );
+
+ if( src[i] == '=' && ++j > 2 )
+ return( MBEDCRYPTO_ERR_BASE64_INVALID_CHARACTER );
+
+ if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
+ return( MBEDCRYPTO_ERR_BASE64_INVALID_CHARACTER );
+
+ if( base64_dec_map[src[i]] < 64 && j != 0 )
+ return( MBEDCRYPTO_ERR_BASE64_INVALID_CHARACTER );
+
+ n++;
+ }
+
+ if( n == 0 )
+ {
+ *olen = 0;
+ return( 0 );
+ }
+
+ /* The following expression is to calculate the following formula without
+ * risk of integer overflow in n:
+ * n = ( ( n * 6 ) + 7 ) >> 3;
+ */
+ n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 );
+ n -= j;
+
+ if( dst == NULL || dlen < n )
+ {
+ *olen = n;
+ return( MBEDCRYPTO_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 -= ( base64_dec_map[*src] == 64 );
+ x = ( x << 6 ) | ( 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(MBEDCRYPTO_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 mbedcrypto_base64_self_test( int verbose )
+{
+ size_t len;
+ const unsigned char *src;
+ unsigned char buffer[128];
+
+ if( verbose != 0 )
+ mbedcrypto_printf( " Base64 encoding test: " );
+
+ src = base64_test_dec;
+
+ if( mbedcrypto_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
+ memcmp( base64_test_enc, buffer, 88 ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+
+ return( 1 );
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n Base64 decoding test: " );
+
+ src = base64_test_enc;
+
+ if( mbedcrypto_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
+ memcmp( base64_test_dec, buffer, 64 ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+
+ return( 1 );
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n\n" );
+
+ return( 0 );
+}
+
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#endif /* MBEDCRYPTO_BASE64_C */
diff --git a/library/bignum.c b/library/bignum.c
new file mode 100644
index 0000000..2b57f9e
--- /dev/null
+++ b/library/bignum.c
@@ -0,0 +1,2468 @@
+/*
+ * 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 Crypto (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(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_BIGNUM_C)
+
+#include "mbedcrypto/bignum.h"
+#include "mbedcrypto/bn_mul.h"
+#include "mbedcrypto/platform_util.h"
+
+#include <string.h>
+
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#define mbedcrypto_printf printf
+#define mbedcrypto_calloc calloc
+#define mbedcrypto_free free
+#endif
+
+#define ciL (sizeof(mbedcrypto_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 ) )
+
+/* Implementation that should never be optimized out by the compiler */
+static void mbedcrypto_mpi_zeroize( mbedcrypto_mpi_uint *v, size_t n )
+{
+ mbedcrypto_platform_zeroize( v, ciL * n );
+}
+
+/*
+ * Initialize one MPI
+ */
+void mbedcrypto_mpi_init( mbedcrypto_mpi *X )
+{
+ if( X == NULL )
+ return;
+
+ X->s = 1;
+ X->n = 0;
+ X->p = NULL;
+}
+
+/*
+ * Unallocate one MPI
+ */
+void mbedcrypto_mpi_free( mbedcrypto_mpi *X )
+{
+ if( X == NULL )
+ return;
+
+ if( X->p != NULL )
+ {
+ mbedcrypto_mpi_zeroize( X->p, X->n );
+ mbedcrypto_free( X->p );
+ }
+
+ X->s = 1;
+ X->n = 0;
+ X->p = NULL;
+}
+
+/*
+ * Enlarge to the specified number of limbs
+ */
+int mbedcrypto_mpi_grow( mbedcrypto_mpi *X, size_t nblimbs )
+{
+ mbedcrypto_mpi_uint *p;
+
+ if( nblimbs > MBEDCRYPTO_MPI_MAX_LIMBS )
+ return( MBEDCRYPTO_ERR_MPI_ALLOC_FAILED );
+
+ if( X->n < nblimbs )
+ {
+ if( ( p = (mbedcrypto_mpi_uint*)mbedcrypto_calloc( nblimbs, ciL ) ) == NULL )
+ return( MBEDCRYPTO_ERR_MPI_ALLOC_FAILED );
+
+ if( X->p != NULL )
+ {
+ memcpy( p, X->p, X->n * ciL );
+ mbedcrypto_mpi_zeroize( X->p, X->n );
+ mbedcrypto_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 mbedcrypto_mpi_shrink( mbedcrypto_mpi *X, size_t nblimbs )
+{
+ mbedcrypto_mpi_uint *p;
+ size_t i;
+
+ /* Actually resize up in this case */
+ if( X->n <= nblimbs )
+ return( mbedcrypto_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 = (mbedcrypto_mpi_uint*)mbedcrypto_calloc( i, ciL ) ) == NULL )
+ return( MBEDCRYPTO_ERR_MPI_ALLOC_FAILED );
+
+ if( X->p != NULL )
+ {
+ memcpy( p, X->p, i * ciL );
+ mbedcrypto_mpi_zeroize( X->p, X->n );
+ mbedcrypto_free( X->p );
+ }
+
+ X->n = i;
+ X->p = p;
+
+ return( 0 );
+}
+
+/*
+ * Copy the contents of Y into X
+ */
+int mbedcrypto_mpi_copy( mbedcrypto_mpi *X, const mbedcrypto_mpi *Y )
+{
+ int ret = 0;
+ size_t i;
+
+ if( X == Y )
+ return( 0 );
+
+ if( Y->p == NULL )
+ {
+ mbedcrypto_mpi_free( X );
+ return( 0 );
+ }
+
+ for( i = Y->n - 1; i > 0; i-- )
+ if( Y->p[i] != 0 )
+ break;
+ i++;
+
+ X->s = Y->s;
+
+ if( X->n < i )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_grow( X, i ) );
+ }
+ else
+ {
+ memset( X->p + i, 0, ( X->n - i ) * ciL );
+ }
+
+ memcpy( X->p, Y->p, i * ciL );
+
+cleanup:
+
+ return( ret );
+}
+
+/*
+ * Swap the contents of X and Y
+ */
+void mbedcrypto_mpi_swap( mbedcrypto_mpi *X, mbedcrypto_mpi *Y )
+{
+ mbedcrypto_mpi T;
+
+ memcpy( &T, X, sizeof( mbedcrypto_mpi ) );
+ memcpy( X, Y, sizeof( mbedcrypto_mpi ) );
+ memcpy( Y, &T, sizeof( mbedcrypto_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 mbedcrypto_mpi_safe_cond_assign( mbedcrypto_mpi *X, const mbedcrypto_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;
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_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 mbedcrypto_mpi_safe_cond_swap( mbedcrypto_mpi *X, mbedcrypto_mpi *Y, unsigned char swap )
+{
+ int ret, s;
+ size_t i;
+ mbedcrypto_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;
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_grow( X, Y->n ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_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 mbedcrypto_mpi_lset( mbedcrypto_mpi *X, mbedcrypto_mpi_sint z )
+{
+ int ret;
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_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 mbedcrypto_mpi_get_bit( const mbedcrypto_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 mbedcrypto_mpi_set_bit( mbedcrypto_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( MBEDCRYPTO_ERR_MPI_BAD_INPUT_DATA );
+
+ if( X->n * biL <= pos )
+ {
+ if( val == 0 )
+ return( 0 );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_grow( X, off + 1 ) );
+ }
+
+ X->p[off] &= ~( (mbedcrypto_mpi_uint) 0x01 << idx );
+ X->p[off] |= (mbedcrypto_mpi_uint) val << idx;
+
+cleanup:
+
+ return( ret );
+}
+
+/*
+ * Return the number of less significant zero-bits
+ */
+size_t mbedcrypto_mpi_lsb( const mbedcrypto_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 mbedcrypto_clz( const mbedcrypto_mpi_uint x )
+{
+ size_t j;
+ mbedcrypto_mpi_uint mask = (mbedcrypto_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 mbedcrypto_mpi_bitlen( const mbedcrypto_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 - mbedcrypto_clz( X->p[i] );
+
+ return( ( i * biL ) + j );
+}
+
+/*
+ * Return the total size in bytes
+ */
+size_t mbedcrypto_mpi_size( const mbedcrypto_mpi *X )
+{
+ return( ( mbedcrypto_mpi_bitlen( X ) + 7 ) >> 3 );
+}
+
+/*
+ * Convert an ASCII character to digit value
+ */
+static int mpi_get_digit( mbedcrypto_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 >= (mbedcrypto_mpi_uint) radix )
+ return( MBEDCRYPTO_ERR_MPI_INVALID_CHARACTER );
+
+ return( 0 );
+}
+
+/*
+ * Import from an ASCII string
+ */
+int mbedcrypto_mpi_read_string( mbedcrypto_mpi *X, int radix, const char *s )
+{
+ int ret;
+ size_t i, j, slen, n;
+ mbedcrypto_mpi_uint d;
+ mbedcrypto_mpi T;
+
+ if( radix < 2 || radix > 16 )
+ return( MBEDCRYPTO_ERR_MPI_BAD_INPUT_DATA );
+
+ mbedcrypto_mpi_init( &T );
+
+ slen = strlen( s );
+
+ if( radix == 16 )
+ {
+ if( slen > MPI_SIZE_T_MAX >> 2 )
+ return( MBEDCRYPTO_ERR_MPI_BAD_INPUT_DATA );
+
+ n = BITS_TO_LIMBS( slen << 2 );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_grow( X, n ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_lset( X, 0 ) );
+
+ for( i = slen, j = 0; i > 0; i--, j++ )
+ {
+ if( i == 1 && s[i - 1] == '-' )
+ {
+ X->s = -1;
+ break;
+ }
+
+ MBEDCRYPTO_MPI_CHK( mpi_get_digit( &d, radix, s[i - 1] ) );
+ X->p[j / ( 2 * ciL )] |= d << ( ( j % ( 2 * ciL ) ) << 2 );
+ }
+ }
+ else
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_lset( X, 0 ) );
+
+ for( i = 0; i < slen; i++ )
+ {
+ if( i == 0 && s[i] == '-' )
+ {
+ X->s = -1;
+ continue;
+ }
+
+ MBEDCRYPTO_MPI_CHK( mpi_get_digit( &d, radix, s[i] ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_int( &T, X, radix ) );
+
+ if( X->s == 1 )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_int( X, &T, d ) );
+ }
+ else
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_int( X, &T, d ) );
+ }
+ }
+ }
+
+cleanup:
+
+ mbedcrypto_mpi_free( &T );
+
+ return( ret );
+}
+
+/*
+ * Helper to write the digits high-order first
+ */
+static int mpi_write_hlp( mbedcrypto_mpi *X, int radix, char **p )
+{
+ int ret;
+ mbedcrypto_mpi_uint r;
+
+ if( radix < 2 || radix > 16 )
+ return( MBEDCRYPTO_ERR_MPI_BAD_INPUT_DATA );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mod_int( &r, X, radix ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_div_int( X, NULL, X, radix ) );
+
+ if( mbedcrypto_mpi_cmp_int( X, 0 ) != 0 )
+ MBEDCRYPTO_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 mbedcrypto_mpi_write_string( const mbedcrypto_mpi *X, int radix,
+ char *buf, size_t buflen, size_t *olen )
+{
+ int ret = 0;
+ size_t n;
+ char *p;
+ mbedcrypto_mpi T;
+
+ if( radix < 2 || radix > 16 )
+ return( MBEDCRYPTO_ERR_MPI_BAD_INPUT_DATA );
+
+ n = mbedcrypto_mpi_bitlen( X );
+ if( radix >= 4 ) n >>= 1;
+ if( radix >= 16 ) n >>= 1;
+ /*
+ * Round up the buffer length to an even value to ensure that there is
+ * enough room for hexadecimal values that can be represented in an odd
+ * number of digits.
+ */
+ n += 3 + ( ( n + 1 ) & 1 );
+
+ if( buflen < n )
+ {
+ *olen = n;
+ return( MBEDCRYPTO_ERR_MPI_BUFFER_TOO_SMALL );
+ }
+
+ p = buf;
+ mbedcrypto_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
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &T, X ) );
+
+ if( T.s == -1 )
+ T.s = 1;
+
+ MBEDCRYPTO_MPI_CHK( mpi_write_hlp( &T, radix, &p ) );
+ }
+
+ *p++ = '\0';
+ *olen = p - buf;
+
+cleanup:
+
+ mbedcrypto_mpi_free( &T );
+
+ return( ret );
+}
+
+#if defined(MBEDCRYPTO_FS_IO)
+/*
+ * Read X from an opened file
+ */
+int mbedcrypto_mpi_read_file( mbedcrypto_mpi *X, int radix, FILE *fin )
+{
+ mbedcrypto_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[ MBEDCRYPTO_MPI_RW_BUFFER_SIZE ];
+
+ memset( s, 0, sizeof( s ) );
+ if( fgets( s, sizeof( s ) - 1, fin ) == NULL )
+ return( MBEDCRYPTO_ERR_MPI_FILE_IO_ERROR );
+
+ slen = strlen( s );
+ if( slen == sizeof( s ) - 2 )
+ return( MBEDCRYPTO_ERR_MPI_BUFFER_TOO_SMALL );
+
+ if( slen > 0 && s[slen - 1] == '\n' ) { slen--; s[slen] = '\0'; }
+ if( slen > 0 && s[slen - 1] == '\r' ) { slen--; s[slen] = '\0'; }
+
+ p = s + slen;
+ while( p-- > s )
+ if( mpi_get_digit( &d, radix, *p ) != 0 )
+ break;
+
+ return( mbedcrypto_mpi_read_string( X, radix, p + 1 ) );
+}
+
+/*
+ * Write X into an opened file (or stdout if fout == NULL)
+ */
+int mbedcrypto_mpi_write_file( const char *p, const mbedcrypto_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[ MBEDCRYPTO_MPI_RW_BUFFER_SIZE ];
+
+ memset( s, 0, sizeof( s ) );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_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( MBEDCRYPTO_ERR_MPI_FILE_IO_ERROR );
+ }
+ else
+ mbedcrypto_printf( "%s%s", p, s );
+
+cleanup:
+
+ return( ret );
+}
+#endif /* MBEDCRYPTO_FS_IO */
+
+/*
+ * Import X from unsigned binary data, big endian
+ */
+int mbedcrypto_mpi_read_binary( mbedcrypto_mpi *X, const unsigned char *buf, size_t buflen )
+{
+ int ret;
+ size_t i, j;
+ size_t const limbs = CHARS_TO_LIMBS( buflen );
+
+ /* Ensure that target MPI has exactly the necessary number of limbs */
+ if( X->n != limbs )
+ {
+ mbedcrypto_mpi_free( X );
+ mbedcrypto_mpi_init( X );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_grow( X, limbs ) );
+ }
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_lset( X, 0 ) );
+
+ for( i = buflen, j = 0; i > 0; i--, j++ )
+ X->p[j / ciL] |= ((mbedcrypto_mpi_uint) buf[i - 1]) << ((j % ciL) << 3);
+
+cleanup:
+
+ return( ret );
+}
+
+/*
+ * Export X into unsigned binary data, big endian
+ */
+int mbedcrypto_mpi_write_binary( const mbedcrypto_mpi *X, unsigned char *buf, size_t buflen )
+{
+ size_t i, j, n;
+
+ n = mbedcrypto_mpi_size( X );
+
+ if( buflen < n )
+ return( MBEDCRYPTO_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 mbedcrypto_mpi_shift_l( mbedcrypto_mpi *X, size_t count )
+{
+ int ret;
+ size_t i, v0, t1;
+ mbedcrypto_mpi_uint r0 = 0, r1;
+
+ v0 = count / (biL );
+ t1 = count & (biL - 1);
+
+ i = mbedcrypto_mpi_bitlen( X ) + count;
+
+ if( X->n * biL < i )
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_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 mbedcrypto_mpi_shift_r( mbedcrypto_mpi *X, size_t count )
+{
+ size_t i, v0, v1;
+ mbedcrypto_mpi_uint r0 = 0, r1;
+
+ v0 = count / biL;
+ v1 = count & (biL - 1);
+
+ if( v0 > X->n || ( v0 == X->n && v1 > 0 ) )
+ return mbedcrypto_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 mbedcrypto_mpi_cmp_abs( const mbedcrypto_mpi *X, const mbedcrypto_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 mbedcrypto_mpi_cmp_mpi( const mbedcrypto_mpi *X, const mbedcrypto_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 mbedcrypto_mpi_cmp_int( const mbedcrypto_mpi *X, mbedcrypto_mpi_sint z )
+{
+ mbedcrypto_mpi Y;
+ mbedcrypto_mpi_uint p[1];
+
+ *p = ( z < 0 ) ? -z : z;
+ Y.s = ( z < 0 ) ? -1 : 1;
+ Y.n = 1;
+ Y.p = p;
+
+ return( mbedcrypto_mpi_cmp_mpi( X, &Y ) );
+}
+
+/*
+ * Unsigned addition: X = |A| + |B| (HAC 14.7)
+ */
+int mbedcrypto_mpi_add_abs( mbedcrypto_mpi *X, const mbedcrypto_mpi *A, const mbedcrypto_mpi *B )
+{
+ int ret;
+ size_t i, j;
+ mbedcrypto_mpi_uint *o, *p, c, tmp;
+
+ if( X == B )
+ {
+ const mbedcrypto_mpi *T = A; A = X; B = T;
+ }
+
+ if( X != A )
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_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;
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_grow( X, j ) );
+
+ o = B->p; p = X->p; c = 0;
+
+ /*
+ * tmp is used because it might happen that p == o
+ */
+ for( i = 0; i < j; i++, o++, p++ )
+ {
+ tmp= *o;
+ *p += c; c = ( *p < c );
+ *p += tmp; c += ( *p < tmp );
+ }
+
+ while( c != 0 )
+ {
+ if( i >= X->n )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_grow( X, i + 1 ) );
+ p = X->p + i;
+ }
+
+ *p += c; c = ( *p < c ); i++; p++;
+ }
+
+cleanup:
+
+ return( ret );
+}
+
+/*
+ * Helper for mbedcrypto_mpi subtraction
+ */
+static void mpi_sub_hlp( size_t n, mbedcrypto_mpi_uint *s, mbedcrypto_mpi_uint *d )
+{
+ size_t i;
+ mbedcrypto_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; d++;
+ }
+}
+
+/*
+ * Unsigned subtraction: X = |A| - |B| (HAC 14.9)
+ */
+int mbedcrypto_mpi_sub_abs( mbedcrypto_mpi *X, const mbedcrypto_mpi *A, const mbedcrypto_mpi *B )
+{
+ mbedcrypto_mpi TB;
+ int ret;
+ size_t n;
+
+ if( mbedcrypto_mpi_cmp_abs( A, B ) < 0 )
+ return( MBEDCRYPTO_ERR_MPI_NEGATIVE_VALUE );
+
+ mbedcrypto_mpi_init( &TB );
+
+ if( X == B )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &TB, B ) );
+ B = &TB;
+ }
+
+ if( X != A )
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_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:
+
+ mbedcrypto_mpi_free( &TB );
+
+ return( ret );
+}
+
+/*
+ * Signed addition: X = A + B
+ */
+int mbedcrypto_mpi_add_mpi( mbedcrypto_mpi *X, const mbedcrypto_mpi *A, const mbedcrypto_mpi *B )
+{
+ int ret, s = A->s;
+
+ if( A->s * B->s < 0 )
+ {
+ if( mbedcrypto_mpi_cmp_abs( A, B ) >= 0 )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_abs( X, A, B ) );
+ X->s = s;
+ }
+ else
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_abs( X, B, A ) );
+ X->s = -s;
+ }
+ }
+ else
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_abs( X, A, B ) );
+ X->s = s;
+ }
+
+cleanup:
+
+ return( ret );
+}
+
+/*
+ * Signed subtraction: X = A - B
+ */
+int mbedcrypto_mpi_sub_mpi( mbedcrypto_mpi *X, const mbedcrypto_mpi *A, const mbedcrypto_mpi *B )
+{
+ int ret, s = A->s;
+
+ if( A->s * B->s > 0 )
+ {
+ if( mbedcrypto_mpi_cmp_abs( A, B ) >= 0 )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_abs( X, A, B ) );
+ X->s = s;
+ }
+ else
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_abs( X, B, A ) );
+ X->s = -s;
+ }
+ }
+ else
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_abs( X, A, B ) );
+ X->s = s;
+ }
+
+cleanup:
+
+ return( ret );
+}
+
+/*
+ * Signed addition: X = A + b
+ */
+int mbedcrypto_mpi_add_int( mbedcrypto_mpi *X, const mbedcrypto_mpi *A, mbedcrypto_mpi_sint b )
+{
+ mbedcrypto_mpi _B;
+ mbedcrypto_mpi_uint p[1];
+
+ p[0] = ( b < 0 ) ? -b : b;
+ _B.s = ( b < 0 ) ? -1 : 1;
+ _B.n = 1;
+ _B.p = p;
+
+ return( mbedcrypto_mpi_add_mpi( X, A, &_B ) );
+}
+
+/*
+ * Signed subtraction: X = A - b
+ */
+int mbedcrypto_mpi_sub_int( mbedcrypto_mpi *X, const mbedcrypto_mpi *A, mbedcrypto_mpi_sint b )
+{
+ mbedcrypto_mpi _B;
+ mbedcrypto_mpi_uint p[1];
+
+ p[0] = ( b < 0 ) ? -b : b;
+ _B.s = ( b < 0 ) ? -1 : 1;
+ _B.n = 1;
+ _B.p = p;
+
+ return( mbedcrypto_mpi_sub_mpi( X, A, &_B ) );
+}
+
+/*
+ * Helper for mbedcrypto_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, mbedcrypto_mpi_uint *s, mbedcrypto_mpi_uint *d, mbedcrypto_mpi_uint b )
+{
+ mbedcrypto_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 mbedcrypto_mpi_mul_mpi( mbedcrypto_mpi *X, const mbedcrypto_mpi *A, const mbedcrypto_mpi *B )
+{
+ int ret;
+ size_t i, j;
+ mbedcrypto_mpi TA, TB;
+
+ mbedcrypto_mpi_init( &TA ); mbedcrypto_mpi_init( &TB );
+
+ if( X == A ) { MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &TA, A ) ); A = &TA; }
+ if( X == B ) { MBEDCRYPTO_MPI_CHK( mbedcrypto_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;
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_grow( X, i + j ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_lset( X, 0 ) );
+
+ for( ; j > 0; j-- )
+ mpi_mul_hlp( i, A->p, X->p + j - 1, B->p[j - 1] );
+
+ X->s = A->s * B->s;
+
+cleanup:
+
+ mbedcrypto_mpi_free( &TB ); mbedcrypto_mpi_free( &TA );
+
+ return( ret );
+}
+
+/*
+ * Baseline multiplication: X = A * b
+ */
+int mbedcrypto_mpi_mul_int( mbedcrypto_mpi *X, const mbedcrypto_mpi *A, mbedcrypto_mpi_uint b )
+{
+ mbedcrypto_mpi _B;
+ mbedcrypto_mpi_uint p[1];
+
+ _B.s = 1;
+ _B.n = 1;
+ _B.p = p;
+ p[0] = b;
+
+ return( mbedcrypto_mpi_mul_mpi( X, A, &_B ) );
+}
+
+/*
+ * Unsigned integer divide - double mbedcrypto_mpi_uint dividend, u1/u0, and
+ * mbedcrypto_mpi_uint divisor, d
+ */
+static mbedcrypto_mpi_uint mbedcrypto_int_div_int( mbedcrypto_mpi_uint u1,
+ mbedcrypto_mpi_uint u0, mbedcrypto_mpi_uint d, mbedcrypto_mpi_uint *r )
+{
+#if defined(MBEDCRYPTO_HAVE_UDBL)
+ mbedcrypto_t_udbl dividend, quotient;
+#else
+ const mbedcrypto_mpi_uint radix = (mbedcrypto_mpi_uint) 1 << biH;
+ const mbedcrypto_mpi_uint uint_halfword_mask = ( (mbedcrypto_mpi_uint) 1 << biH ) - 1;
+ mbedcrypto_mpi_uint d0, d1, q0, q1, rAX, r0, quotient;
+ mbedcrypto_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(MBEDCRYPTO_HAVE_UDBL)
+ dividend = (mbedcrypto_t_udbl) u1 << biL;
+ dividend |= (mbedcrypto_t_udbl) u0;
+ quotient = dividend / d;
+ if( quotient > ( (mbedcrypto_t_udbl) 1 << biL ) - 1 )
+ quotient = ( (mbedcrypto_t_udbl) 1 << biL ) - 1;
+
+ if( r != NULL )
+ *r = (mbedcrypto_mpi_uint)( dividend - (quotient * d ) );
+
+ return (mbedcrypto_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 = mbedcrypto_clz( d );
+ d = d << s;
+
+ u1 = u1 << s;
+ u1 |= ( u0 >> ( biL - s ) ) & ( -(mbedcrypto_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 mbedcrypto_mpi: A = Q * B + R (HAC 14.20)
+ */
+int mbedcrypto_mpi_div_mpi( mbedcrypto_mpi *Q, mbedcrypto_mpi *R, const mbedcrypto_mpi *A, const mbedcrypto_mpi *B )
+{
+ int ret;
+ size_t i, n, t, k;
+ mbedcrypto_mpi X, Y, Z, T1, T2;
+
+ if( mbedcrypto_mpi_cmp_int( B, 0 ) == 0 )
+ return( MBEDCRYPTO_ERR_MPI_DIVISION_BY_ZERO );
+
+ mbedcrypto_mpi_init( &X ); mbedcrypto_mpi_init( &Y ); mbedcrypto_mpi_init( &Z );
+ mbedcrypto_mpi_init( &T1 ); mbedcrypto_mpi_init( &T2 );
+
+ if( mbedcrypto_mpi_cmp_abs( A, B ) < 0 )
+ {
+ if( Q != NULL ) MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_lset( Q, 0 ) );
+ if( R != NULL ) MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( R, A ) );
+ return( 0 );
+ }
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &X, A ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &Y, B ) );
+ X.s = Y.s = 1;
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_grow( &Z, A->n + 2 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_lset( &Z, 0 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_grow( &T1, 2 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_grow( &T2, 3 ) );
+
+ k = mbedcrypto_mpi_bitlen( &Y ) % biL;
+ if( k < biL - 1 )
+ {
+ k = biL - 1 - k;
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_l( &X, k ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_l( &Y, k ) );
+ }
+ else k = 0;
+
+ n = X.n - 1;
+ t = Y.n - 1;
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_l( &Y, biL * ( n - t ) ) );
+
+ while( mbedcrypto_mpi_cmp_mpi( &X, &Y ) >= 0 )
+ {
+ Z.p[n - t]++;
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &X, &X, &Y ) );
+ }
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_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] = mbedcrypto_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]--;
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_lset( &T1, 0 ) );
+ T1.p[0] = ( t < 1 ) ? 0 : Y.p[t - 1];
+ T1.p[1] = Y.p[t];
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_int( &T1, &T1, Z.p[i - t - 1] ) );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_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( mbedcrypto_mpi_cmp_mpi( &T1, &T2 ) > 0 );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_int( &T1, &Y, Z.p[i - t - 1] ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_l( &T1, biL * ( i - t - 1 ) ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &X, &X, &T1 ) );
+
+ if( mbedcrypto_mpi_cmp_int( &X, 0 ) < 0 )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &T1, &Y ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_l( &T1, biL * ( i - t - 1 ) ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_mpi( &X, &X, &T1 ) );
+ Z.p[i - t - 1]--;
+ }
+ }
+
+ if( Q != NULL )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( Q, &Z ) );
+ Q->s = A->s * B->s;
+ }
+
+ if( R != NULL )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_r( &X, k ) );
+ X.s = A->s;
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( R, &X ) );
+
+ if( mbedcrypto_mpi_cmp_int( R, 0 ) == 0 )
+ R->s = 1;
+ }
+
+cleanup:
+
+ mbedcrypto_mpi_free( &X ); mbedcrypto_mpi_free( &Y ); mbedcrypto_mpi_free( &Z );
+ mbedcrypto_mpi_free( &T1 ); mbedcrypto_mpi_free( &T2 );
+
+ return( ret );
+}
+
+/*
+ * Division by int: A = Q * b + R
+ */
+int mbedcrypto_mpi_div_int( mbedcrypto_mpi *Q, mbedcrypto_mpi *R, const mbedcrypto_mpi *A, mbedcrypto_mpi_sint b )
+{
+ mbedcrypto_mpi _B;
+ mbedcrypto_mpi_uint p[1];
+
+ p[0] = ( b < 0 ) ? -b : b;
+ _B.s = ( b < 0 ) ? -1 : 1;
+ _B.n = 1;
+ _B.p = p;
+
+ return( mbedcrypto_mpi_div_mpi( Q, R, A, &_B ) );
+}
+
+/*
+ * Modulo: R = A mod B
+ */
+int mbedcrypto_mpi_mod_mpi( mbedcrypto_mpi *R, const mbedcrypto_mpi *A, const mbedcrypto_mpi *B )
+{
+ int ret;
+
+ if( mbedcrypto_mpi_cmp_int( B, 0 ) < 0 )
+ return( MBEDCRYPTO_ERR_MPI_NEGATIVE_VALUE );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_div_mpi( NULL, R, A, B ) );
+
+ while( mbedcrypto_mpi_cmp_int( R, 0 ) < 0 )
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_mpi( R, R, B ) );
+
+ while( mbedcrypto_mpi_cmp_mpi( R, B ) >= 0 )
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( R, R, B ) );
+
+cleanup:
+
+ return( ret );
+}
+
+/*
+ * Modulo: r = A mod b
+ */
+int mbedcrypto_mpi_mod_int( mbedcrypto_mpi_uint *r, const mbedcrypto_mpi *A, mbedcrypto_mpi_sint b )
+{
+ size_t i;
+ mbedcrypto_mpi_uint x, y, z;
+
+ if( b == 0 )
+ return( MBEDCRYPTO_ERR_MPI_DIVISION_BY_ZERO );
+
+ if( b < 0 )
+ return( MBEDCRYPTO_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( mbedcrypto_mpi_uint *mm, const mbedcrypto_mpi *N )
+{
+ mbedcrypto_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 int mpi_montmul( mbedcrypto_mpi *A, const mbedcrypto_mpi *B, const mbedcrypto_mpi *N, mbedcrypto_mpi_uint mm,
+ const mbedcrypto_mpi *T )
+{
+ size_t i, n, m;
+ mbedcrypto_mpi_uint u0, u1, *d;
+
+ if( T->n < N->n + 1 || T->p == NULL )
+ return( MBEDCRYPTO_ERR_MPI_BAD_INPUT_DATA );
+
+ 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( mbedcrypto_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 );
+
+ return( 0 );
+}
+
+/*
+ * Montgomery reduction: A = A * R^-1 mod N
+ */
+static int mpi_montred( mbedcrypto_mpi *A, const mbedcrypto_mpi *N, mbedcrypto_mpi_uint mm, const mbedcrypto_mpi *T )
+{
+ mbedcrypto_mpi_uint z = 1;
+ mbedcrypto_mpi U;
+
+ U.n = U.s = (int) z;
+ U.p = &z;
+
+ return( mpi_montmul( A, &U, N, mm, T ) );
+}
+
+/*
+ * Sliding-window exponentiation: X = A^E mod N (HAC 14.85)
+ */
+int mbedcrypto_mpi_exp_mod( mbedcrypto_mpi *X, const mbedcrypto_mpi *A, const mbedcrypto_mpi *E, const mbedcrypto_mpi *N, mbedcrypto_mpi *_RR )
+{
+ int ret;
+ size_t wbits, wsize, one = 1;
+ size_t i, j, nblimbs;
+ size_t bufsize, nbits;
+ mbedcrypto_mpi_uint ei, mm, state;
+ mbedcrypto_mpi RR, T, W[ 2 << MBEDCRYPTO_MPI_WINDOW_SIZE ], Apos;
+ int neg;
+
+ if( mbedcrypto_mpi_cmp_int( N, 0 ) <= 0 || ( N->p[0] & 1 ) == 0 )
+ return( MBEDCRYPTO_ERR_MPI_BAD_INPUT_DATA );
+
+ if( mbedcrypto_mpi_cmp_int( E, 0 ) < 0 )
+ return( MBEDCRYPTO_ERR_MPI_BAD_INPUT_DATA );
+
+ /*
+ * Init temps and window size
+ */
+ mpi_montg_init( &mm, N );
+ mbedcrypto_mpi_init( &RR ); mbedcrypto_mpi_init( &T );
+ mbedcrypto_mpi_init( &Apos );
+ memset( W, 0, sizeof( W ) );
+
+ i = mbedcrypto_mpi_bitlen( E );
+
+ wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 :
+ ( i > 79 ) ? 4 : ( i > 23 ) ? 3 : 1;
+
+ if( wsize > MBEDCRYPTO_MPI_WINDOW_SIZE )
+ wsize = MBEDCRYPTO_MPI_WINDOW_SIZE;
+
+ j = N->n + 1;
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_grow( X, j ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_grow( &W[1], j ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_grow( &T, j * 2 ) );
+
+ /*
+ * Compensate for negative A (and correct at the end)
+ */
+ neg = ( A->s == -1 );
+ if( neg )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &Apos, A ) );
+ Apos.s = 1;
+ A = &Apos;
+ }
+
+ /*
+ * If 1st call, pre-compute R^2 mod N
+ */
+ if( _RR == NULL || _RR->p == NULL )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_lset( &RR, 1 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_l( &RR, N->n * 2 * biL ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mod_mpi( &RR, &RR, N ) );
+
+ if( _RR != NULL )
+ memcpy( _RR, &RR, sizeof( mbedcrypto_mpi ) );
+ }
+ else
+ memcpy( &RR, _RR, sizeof( mbedcrypto_mpi ) );
+
+ /*
+ * W[1] = A * R^2 * R^-1 mod N = A * R mod N
+ */
+ if( mbedcrypto_mpi_cmp_mpi( A, N ) >= 0 )
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mod_mpi( &W[1], A, N ) );
+ else
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &W[1], A ) );
+
+ MBEDCRYPTO_MPI_CHK( mpi_montmul( &W[1], &RR, N, mm, &T ) );
+
+ /*
+ * X = R^2 * R^-1 mod N = R mod N
+ */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( X, &RR ) );
+ MBEDCRYPTO_MPI_CHK( mpi_montred( X, N, mm, &T ) );
+
+ if( wsize > 1 )
+ {
+ /*
+ * W[1 << (wsize - 1)] = W[1] ^ (wsize - 1)
+ */
+ j = one << ( wsize - 1 );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_grow( &W[j], N->n + 1 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &W[j], &W[1] ) );
+
+ for( i = 0; i < wsize - 1; i++ )
+ MBEDCRYPTO_MPI_CHK( mpi_montmul( &W[j], &W[j], N, mm, &T ) );
+
+ /*
+ * W[i] = W[i - 1] * W[1]
+ */
+ for( i = j + 1; i < ( one << wsize ); i++ )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_grow( &W[i], N->n + 1 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &W[i], &W[i - 1] ) );
+
+ MBEDCRYPTO_MPI_CHK( 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( mbedcrypto_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
+ */
+ MBEDCRYPTO_MPI_CHK( 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++ )
+ MBEDCRYPTO_MPI_CHK( mpi_montmul( X, X, N, mm, &T ) );
+
+ /*
+ * X = X * W[wbits] R^-1 mod N
+ */
+ MBEDCRYPTO_MPI_CHK( mpi_montmul( X, &W[wbits], N, mm, &T ) );
+
+ state--;
+ nbits = 0;
+ wbits = 0;
+ }
+ }
+
+ /*
+ * process the remaining bits
+ */
+ for( i = 0; i < nbits; i++ )
+ {
+ MBEDCRYPTO_MPI_CHK( mpi_montmul( X, X, N, mm, &T ) );
+
+ wbits <<= 1;
+
+ if( ( wbits & ( one << wsize ) ) != 0 )
+ MBEDCRYPTO_MPI_CHK( mpi_montmul( X, &W[1], N, mm, &T ) );
+ }
+
+ /*
+ * X = A^E * R * R^-1 mod N = A^E mod N
+ */
+ MBEDCRYPTO_MPI_CHK( mpi_montred( X, N, mm, &T ) );
+
+ if( neg && E->n != 0 && ( E->p[0] & 1 ) != 0 )
+ {
+ X->s = -1;
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_mpi( X, N, X ) );
+ }
+
+cleanup:
+
+ for( i = ( one << ( wsize - 1 ) ); i < ( one << wsize ); i++ )
+ mbedcrypto_mpi_free( &W[i] );
+
+ mbedcrypto_mpi_free( &W[1] ); mbedcrypto_mpi_free( &T ); mbedcrypto_mpi_free( &Apos );
+
+ if( _RR == NULL || _RR->p == NULL )
+ mbedcrypto_mpi_free( &RR );
+
+ return( ret );
+}
+
+/*
+ * Greatest common divisor: G = gcd(A, B) (HAC 14.54)
+ */
+int mbedcrypto_mpi_gcd( mbedcrypto_mpi *G, const mbedcrypto_mpi *A, const mbedcrypto_mpi *B )
+{
+ int ret;
+ size_t lz, lzt;
+ mbedcrypto_mpi TG, TA, TB;
+
+ mbedcrypto_mpi_init( &TG ); mbedcrypto_mpi_init( &TA ); mbedcrypto_mpi_init( &TB );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &TA, A ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &TB, B ) );
+
+ lz = mbedcrypto_mpi_lsb( &TA );
+ lzt = mbedcrypto_mpi_lsb( &TB );
+
+ if( lzt < lz )
+ lz = lzt;
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_r( &TA, lz ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_r( &TB, lz ) );
+
+ TA.s = TB.s = 1;
+
+ while( mbedcrypto_mpi_cmp_int( &TA, 0 ) != 0 )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_r( &TA, mbedcrypto_mpi_lsb( &TA ) ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_r( &TB, mbedcrypto_mpi_lsb( &TB ) ) );
+
+ if( mbedcrypto_mpi_cmp_mpi( &TA, &TB ) >= 0 )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_abs( &TA, &TA, &TB ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_r( &TA, 1 ) );
+ }
+ else
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_abs( &TB, &TB, &TA ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_r( &TB, 1 ) );
+ }
+ }
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_l( &TB, lz ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( G, &TB ) );
+
+cleanup:
+
+ mbedcrypto_mpi_free( &TG ); mbedcrypto_mpi_free( &TA ); mbedcrypto_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 mbedcrypto_mpi_fill_random( mbedcrypto_mpi *X, size_t size,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng )
+{
+ int ret;
+ unsigned char buf[MBEDCRYPTO_MPI_MAX_SIZE];
+
+ if( size > MBEDCRYPTO_MPI_MAX_SIZE )
+ return( MBEDCRYPTO_ERR_MPI_BAD_INPUT_DATA );
+
+ MBEDCRYPTO_MPI_CHK( f_rng( p_rng, buf, size ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_binary( X, buf, size ) );
+
+cleanup:
+ mbedcrypto_platform_zeroize( buf, sizeof( buf ) );
+ return( ret );
+}
+
+/*
+ * Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64)
+ */
+int mbedcrypto_mpi_inv_mod( mbedcrypto_mpi *X, const mbedcrypto_mpi *A, const mbedcrypto_mpi *N )
+{
+ int ret;
+ mbedcrypto_mpi G, TA, TU, U1, U2, TB, TV, V1, V2;
+
+ if( mbedcrypto_mpi_cmp_int( N, 1 ) <= 0 )
+ return( MBEDCRYPTO_ERR_MPI_BAD_INPUT_DATA );
+
+ mbedcrypto_mpi_init( &TA ); mbedcrypto_mpi_init( &TU ); mbedcrypto_mpi_init( &U1 ); mbedcrypto_mpi_init( &U2 );
+ mbedcrypto_mpi_init( &G ); mbedcrypto_mpi_init( &TB ); mbedcrypto_mpi_init( &TV );
+ mbedcrypto_mpi_init( &V1 ); mbedcrypto_mpi_init( &V2 );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_gcd( &G, A, N ) );
+
+ if( mbedcrypto_mpi_cmp_int( &G, 1 ) != 0 )
+ {
+ ret = MBEDCRYPTO_ERR_MPI_NOT_ACCEPTABLE;
+ goto cleanup;
+ }
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mod_mpi( &TA, A, N ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &TU, &TA ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &TB, N ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &TV, N ) );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_lset( &U1, 1 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_lset( &U2, 0 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_lset( &V1, 0 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_lset( &V2, 1 ) );
+
+ do
+ {
+ while( ( TU.p[0] & 1 ) == 0 )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_r( &TU, 1 ) );
+
+ if( ( U1.p[0] & 1 ) != 0 || ( U2.p[0] & 1 ) != 0 )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_mpi( &U1, &U1, &TB ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &U2, &U2, &TA ) );
+ }
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_r( &U1, 1 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_r( &U2, 1 ) );
+ }
+
+ while( ( TV.p[0] & 1 ) == 0 )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_r( &TV, 1 ) );
+
+ if( ( V1.p[0] & 1 ) != 0 || ( V2.p[0] & 1 ) != 0 )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_mpi( &V1, &V1, &TB ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &V2, &V2, &TA ) );
+ }
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_r( &V1, 1 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_r( &V2, 1 ) );
+ }
+
+ if( mbedcrypto_mpi_cmp_mpi( &TU, &TV ) >= 0 )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &TU, &TU, &TV ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &U1, &U1, &V1 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &U2, &U2, &V2 ) );
+ }
+ else
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &TV, &TV, &TU ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &V1, &V1, &U1 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &V2, &V2, &U2 ) );
+ }
+ }
+ while( mbedcrypto_mpi_cmp_int( &TU, 0 ) != 0 );
+
+ while( mbedcrypto_mpi_cmp_int( &V1, 0 ) < 0 )
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_mpi( &V1, &V1, N ) );
+
+ while( mbedcrypto_mpi_cmp_mpi( &V1, N ) >= 0 )
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &V1, &V1, N ) );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( X, &V1 ) );
+
+cleanup:
+
+ mbedcrypto_mpi_free( &TA ); mbedcrypto_mpi_free( &TU ); mbedcrypto_mpi_free( &U1 ); mbedcrypto_mpi_free( &U2 );
+ mbedcrypto_mpi_free( &G ); mbedcrypto_mpi_free( &TB ); mbedcrypto_mpi_free( &TV );
+ mbedcrypto_mpi_free( &V1 ); mbedcrypto_mpi_free( &V2 );
+
+ return( ret );
+}
+
+#if defined(MBEDCRYPTO_GENPRIME)
+
+static const int small_prime[] =
+{
+ 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
+ * MBEDCRYPTO_ERR_MPI_NOT_ACCEPTABLE: certain non-prime
+ * other negative: error
+ */
+static int mpi_check_small_factors( const mbedcrypto_mpi *X )
+{
+ int ret = 0;
+ size_t i;
+ mbedcrypto_mpi_uint r;
+
+ if( ( X->p[0] & 1 ) == 0 )
+ return( MBEDCRYPTO_ERR_MPI_NOT_ACCEPTABLE );
+
+ for( i = 0; small_prime[i] > 0; i++ )
+ {
+ if( mbedcrypto_mpi_cmp_int( X, small_prime[i] ) <= 0 )
+ return( 1 );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mod_int( &r, X, small_prime[i] ) );
+
+ if( r == 0 )
+ return( MBEDCRYPTO_ERR_MPI_NOT_ACCEPTABLE );
+ }
+
+cleanup:
+ return( ret );
+}
+
+/*
+ * Miller-Rabin pseudo-primality test (HAC 4.24)
+ */
+static int mpi_miller_rabin( const mbedcrypto_mpi *X,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng )
+{
+ int ret, count;
+ size_t i, j, k, n, s;
+ mbedcrypto_mpi W, R, T, A, RR;
+
+ mbedcrypto_mpi_init( &W ); mbedcrypto_mpi_init( &R ); mbedcrypto_mpi_init( &T ); mbedcrypto_mpi_init( &A );
+ mbedcrypto_mpi_init( &RR );
+
+ /*
+ * W = |X| - 1
+ * R = W >> lsb( W )
+ */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_int( &W, X, 1 ) );
+ s = mbedcrypto_mpi_lsb( &W );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &R, &W ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_r( &R, s ) );
+
+ i = mbedcrypto_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
+ */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) );
+
+ if( mbedcrypto_mpi_cmp_mpi( &A, &W ) >= 0 )
+ {
+ j = mbedcrypto_mpi_bitlen( &A ) - mbedcrypto_mpi_bitlen( &W );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_r( &A, j + 1 ) );
+ }
+ A.p[0] |= 3;
+
+ count = 0;
+ do {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) );
+
+ j = mbedcrypto_mpi_bitlen( &A );
+ k = mbedcrypto_mpi_bitlen( &W );
+ if (j > k) {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_r( &A, j - k ) );
+ }
+
+ if (count++ > 30) {
+ return MBEDCRYPTO_ERR_MPI_NOT_ACCEPTABLE;
+ }
+
+ } while ( mbedcrypto_mpi_cmp_mpi( &A, &W ) >= 0 ||
+ mbedcrypto_mpi_cmp_int( &A, 1 ) <= 0 );
+
+ /*
+ * A = A^R mod |X|
+ */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_exp_mod( &A, &A, &R, X, &RR ) );
+
+ if( mbedcrypto_mpi_cmp_mpi( &A, &W ) == 0 ||
+ mbedcrypto_mpi_cmp_int( &A, 1 ) == 0 )
+ continue;
+
+ j = 1;
+ while( j < s && mbedcrypto_mpi_cmp_mpi( &A, &W ) != 0 )
+ {
+ /*
+ * A = A * A mod |X|
+ */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &T, &A, &A ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mod_mpi( &A, &T, X ) );
+
+ if( mbedcrypto_mpi_cmp_int( &A, 1 ) == 0 )
+ break;
+
+ j++;
+ }
+
+ /*
+ * not prime if A != |X| - 1 or A == 1
+ */
+ if( mbedcrypto_mpi_cmp_mpi( &A, &W ) != 0 ||
+ mbedcrypto_mpi_cmp_int( &A, 1 ) == 0 )
+ {
+ ret = MBEDCRYPTO_ERR_MPI_NOT_ACCEPTABLE;
+ break;
+ }
+ }
+
+cleanup:
+ mbedcrypto_mpi_free( &W ); mbedcrypto_mpi_free( &R ); mbedcrypto_mpi_free( &T ); mbedcrypto_mpi_free( &A );
+ mbedcrypto_mpi_free( &RR );
+
+ return( ret );
+}
+
+/*
+ * Pseudo-primality test: small factors, then Miller-Rabin
+ */
+int mbedcrypto_mpi_is_prime( const mbedcrypto_mpi *X,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng )
+{
+ int ret;
+ mbedcrypto_mpi XX;
+
+ XX.s = 1;
+ XX.n = X->n;
+ XX.p = X->p;
+
+ if( mbedcrypto_mpi_cmp_int( &XX, 0 ) == 0 ||
+ mbedcrypto_mpi_cmp_int( &XX, 1 ) == 0 )
+ return( MBEDCRYPTO_ERR_MPI_NOT_ACCEPTABLE );
+
+ if( mbedcrypto_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
+ *
+ * If dh_flag is 0 and nbits is at least 1024, then the procedure
+ * follows the RSA probably-prime generation method of FIPS 186-4.
+ * NB. FIPS 186-4 only allows the specific bit lengths of 1024 and 1536.
+ */
+int mbedcrypto_mpi_gen_prime( mbedcrypto_mpi *X, size_t nbits, int dh_flag,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng )
+{
+#ifdef MBEDCRYPTO_HAVE_INT64
+// ceil(2^63.5)
+#define CEIL_MAXUINT_DIV_SQRT2 0xb504f333f9de6485ULL
+#else
+// ceil(2^31.5)
+#define CEIL_MAXUINT_DIV_SQRT2 0xb504f334U
+#endif
+ int ret = MBEDCRYPTO_ERR_MPI_NOT_ACCEPTABLE;
+ size_t k, n;
+ mbedcrypto_mpi_uint r;
+ mbedcrypto_mpi Y;
+
+ if( nbits < 3 || nbits > MBEDCRYPTO_MPI_MAX_BITS )
+ return( MBEDCRYPTO_ERR_MPI_BAD_INPUT_DATA );
+
+ mbedcrypto_mpi_init( &Y );
+
+ n = BITS_TO_LIMBS( nbits );
+
+ while( 1 )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_fill_random( X, n * ciL, f_rng, p_rng ) );
+ /* make sure generated number is at least (nbits-1)+0.5 bits (FIPS 186-4 §B.3.3 steps 4.4, 5.5) */
+ if( X->p[n-1] < CEIL_MAXUINT_DIV_SQRT2 ) continue;
+
+ k = n * biL;
+ if( k > nbits ) MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_r( X, k - nbits ) );
+ X->p[0] |= 1;
+
+ if( dh_flag == 0 )
+ {
+ ret = mbedcrypto_mpi_is_prime( X, f_rng, p_rng );
+
+ if( ret != MBEDCRYPTO_ERR_MPI_NOT_ACCEPTABLE )
+ goto cleanup;
+ }
+ 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;
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mod_int( &r, X, 3 ) );
+ if( r == 0 )
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_int( X, X, 8 ) );
+ else if( r == 1 )
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_int( X, X, 4 ) );
+
+ /* Set Y = (X-1) / 2, which is X / 2 because X is odd */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &Y, X ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_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 )
+ goto cleanup;
+
+ if( ret != MBEDCRYPTO_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.
+ */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_int( X, X, 12 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_int( &Y, &Y, 6 ) );
+ }
+ }
+ }
+
+cleanup:
+
+ mbedcrypto_mpi_free( &Y );
+
+ return( ret );
+}
+
+#endif /* MBEDCRYPTO_GENPRIME */
+
+#if defined(MBEDCRYPTO_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 mbedcrypto_mpi_self_test( int verbose )
+{
+ int ret, i;
+ mbedcrypto_mpi A, E, N, X, Y, U, V;
+
+ mbedcrypto_mpi_init( &A ); mbedcrypto_mpi_init( &E ); mbedcrypto_mpi_init( &N ); mbedcrypto_mpi_init( &X );
+ mbedcrypto_mpi_init( &Y ); mbedcrypto_mpi_init( &U ); mbedcrypto_mpi_init( &V );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_string( &A, 16,
+ "EFE021C2645FD1DC586E69184AF4A31E" \
+ "D5F53E93B5F123FA41680867BA110131" \
+ "944FE7952E2517337780CB0DB80E61AA" \
+ "E7C8DDC6C5C6AADEB34EB38A2F40D5E6" ) );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_string( &E, 16,
+ "B2E7EFD37075B9F03FF989C7C5051C20" \
+ "34D2A323810251127E7BF8625A4F49A5" \
+ "F3E27F4DA8BD59C47D6DAABA4C8127BD" \
+ "5B5C25763222FEFCCFC38B832366C29E" ) );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_string( &N, 16,
+ "0066A198186C18C10B2F5ED9B522752A" \
+ "9830B69916E535C8F047518A889A43A5" \
+ "94B6BED27A168D31D4A52F88925AA8F5" ) );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &X, &A, &N ) );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_string( &U, 16,
+ "602AB7ECA597A3D6B56FF9829A5E8B85" \
+ "9E857EA95A03512E2BAE7391688D264A" \
+ "A5663B0341DB9CCFD2C4C5F421FEC814" \
+ "8001B72E848A38CAE1C65F78E56ABDEF" \
+ "E12D3C039B8A02D6BE593F0BBBDA56F1" \
+ "ECF677152EF804370C1A305CAF3B5BF1" \
+ "30879B56C61DE584A0F53A2447A51E" ) );
+
+ if( verbose != 0 )
+ mbedcrypto_printf( " MPI test #1 (mul_mpi): " );
+
+ if( mbedcrypto_mpi_cmp_mpi( &X, &U ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+
+ ret = 1;
+ goto cleanup;
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_div_mpi( &X, &Y, &A, &N ) );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_string( &U, 16,
+ "256567336059E52CAE22925474705F39A94" ) );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_string( &V, 16,
+ "6613F26162223DF488E9CD48CC132C7A" \
+ "0AC93C701B001B092E4E5B9F73BCD27B" \
+ "9EE50D0657C77F374E903CDFA4C642" ) );
+
+ if( verbose != 0 )
+ mbedcrypto_printf( " MPI test #2 (div_mpi): " );
+
+ if( mbedcrypto_mpi_cmp_mpi( &X, &U ) != 0 ||
+ mbedcrypto_mpi_cmp_mpi( &Y, &V ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+
+ ret = 1;
+ goto cleanup;
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_exp_mod( &X, &A, &E, &N, NULL ) );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_string( &U, 16,
+ "36E139AEA55215609D2816998ED020BB" \
+ "BD96C37890F65171D948E9BC7CBAA4D9" \
+ "325D24D6A3C12710F10A09FA08AB87" ) );
+
+ if( verbose != 0 )
+ mbedcrypto_printf( " MPI test #3 (exp_mod): " );
+
+ if( mbedcrypto_mpi_cmp_mpi( &X, &U ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+
+ ret = 1;
+ goto cleanup;
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_inv_mod( &X, &A, &N ) );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_string( &U, 16,
+ "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \
+ "C3DBA76456363A10869622EAC2DD84EC" \
+ "C5B8A74DAC4D09E03B5E0BE779F2DF61" ) );
+
+ if( verbose != 0 )
+ mbedcrypto_printf( " MPI test #4 (inv_mod): " );
+
+ if( mbedcrypto_mpi_cmp_mpi( &X, &U ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+
+ ret = 1;
+ goto cleanup;
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+
+ if( verbose != 0 )
+ mbedcrypto_printf( " MPI test #5 (simple gcd): " );
+
+ for( i = 0; i < GCD_PAIR_COUNT; i++ )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_lset( &X, gcd_pairs[i][0] ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_lset( &Y, gcd_pairs[i][1] ) );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_gcd( &A, &X, &Y ) );
+
+ if( mbedcrypto_mpi_cmp_int( &A, gcd_pairs[i][2] ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed at %d\n", i );
+
+ ret = 1;
+ goto cleanup;
+ }
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+
+cleanup:
+
+ if( ret != 0 && verbose != 0 )
+ mbedcrypto_printf( "Unexpected error, return code = %08X\n", ret );
+
+ mbedcrypto_mpi_free( &A ); mbedcrypto_mpi_free( &E ); mbedcrypto_mpi_free( &N ); mbedcrypto_mpi_free( &X );
+ mbedcrypto_mpi_free( &Y ); mbedcrypto_mpi_free( &U ); mbedcrypto_mpi_free( &V );
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "\n" );
+
+ return( ret );
+}
+
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#endif /* MBEDCRYPTO_BIGNUM_C */
diff --git a/library/blowfish.c b/library/blowfish.c
new file mode 100644
index 0000000..df158ad
--- /dev/null
+++ b/library/blowfish.c
@@ -0,0 +1,652 @@
+/*
+ * 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 Crypto (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(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_BLOWFISH_C)
+
+#include "mbedcrypto/blowfish.h"
+#include "mbedcrypto/platform_util.h"
+
+#include <string.h>
+
+#if !defined(MBEDCRYPTO_BLOWFISH_ALT)
+
+/*
+ * 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[MBEDCRYPTO_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( mbedcrypto_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( mbedcrypto_blowfish_context *ctx, uint32_t *xl, uint32_t *xr )
+{
+ uint32_t Xl, Xr, temp;
+ short i;
+
+ Xl = *xl;
+ Xr = *xr;
+
+ for( i = 0; i < MBEDCRYPTO_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[MBEDCRYPTO_BLOWFISH_ROUNDS];
+ Xl = Xl ^ ctx->P[MBEDCRYPTO_BLOWFISH_ROUNDS + 1];
+
+ *xl = Xl;
+ *xr = Xr;
+}
+
+static void blowfish_dec( mbedcrypto_blowfish_context *ctx, uint32_t *xl, uint32_t *xr )
+{
+ uint32_t Xl, Xr, temp;
+ short i;
+
+ Xl = *xl;
+ Xr = *xr;
+
+ for( i = MBEDCRYPTO_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 mbedcrypto_blowfish_init( mbedcrypto_blowfish_context *ctx )
+{
+ memset( ctx, 0, sizeof( mbedcrypto_blowfish_context ) );
+}
+
+void mbedcrypto_blowfish_free( mbedcrypto_blowfish_context *ctx )
+{
+ if( ctx == NULL )
+ return;
+
+ mbedcrypto_platform_zeroize( ctx, sizeof( mbedcrypto_blowfish_context ) );
+}
+
+/*
+ * Blowfish key schedule
+ */
+int mbedcrypto_blowfish_setkey( mbedcrypto_blowfish_context *ctx, const unsigned char *key,
+ unsigned int keybits )
+{
+ unsigned int i, j, k;
+ uint32_t data, datal, datar;
+
+ if( keybits < MBEDCRYPTO_BLOWFISH_MIN_KEY_BITS || keybits > MBEDCRYPTO_BLOWFISH_MAX_KEY_BITS ||
+ ( keybits % 8 ) )
+ {
+ return( MBEDCRYPTO_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 < MBEDCRYPTO_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 < MBEDCRYPTO_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 mbedcrypto_blowfish_crypt_ecb( mbedcrypto_blowfish_context *ctx,
+ int mode,
+ const unsigned char input[MBEDCRYPTO_BLOWFISH_BLOCKSIZE],
+ unsigned char output[MBEDCRYPTO_BLOWFISH_BLOCKSIZE] )
+{
+ uint32_t X0, X1;
+
+ GET_UINT32_BE( X0, input, 0 );
+ GET_UINT32_BE( X1, input, 4 );
+
+ if( mode == MBEDCRYPTO_BLOWFISH_DECRYPT )
+ {
+ blowfish_dec( ctx, &X0, &X1 );
+ }
+ else /* MBEDCRYPTO_BLOWFISH_ENCRYPT */
+ {
+ blowfish_enc( ctx, &X0, &X1 );
+ }
+
+ PUT_UINT32_BE( X0, output, 0 );
+ PUT_UINT32_BE( X1, output, 4 );
+
+ return( 0 );
+}
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+/*
+ * Blowfish-CBC buffer encryption/decryption
+ */
+int mbedcrypto_blowfish_crypt_cbc( mbedcrypto_blowfish_context *ctx,
+ int mode,
+ size_t length,
+ unsigned char iv[MBEDCRYPTO_BLOWFISH_BLOCKSIZE],
+ const unsigned char *input,
+ unsigned char *output )
+{
+ int i;
+ unsigned char temp[MBEDCRYPTO_BLOWFISH_BLOCKSIZE];
+
+ if( length % MBEDCRYPTO_BLOWFISH_BLOCKSIZE )
+ return( MBEDCRYPTO_ERR_BLOWFISH_INVALID_INPUT_LENGTH );
+
+ if( mode == MBEDCRYPTO_BLOWFISH_DECRYPT )
+ {
+ while( length > 0 )
+ {
+ memcpy( temp, input, MBEDCRYPTO_BLOWFISH_BLOCKSIZE );
+ mbedcrypto_blowfish_crypt_ecb( ctx, mode, input, output );
+
+ for( i = 0; i < MBEDCRYPTO_BLOWFISH_BLOCKSIZE;i++ )
+ output[i] = (unsigned char)( output[i] ^ iv[i] );
+
+ memcpy( iv, temp, MBEDCRYPTO_BLOWFISH_BLOCKSIZE );
+
+ input += MBEDCRYPTO_BLOWFISH_BLOCKSIZE;
+ output += MBEDCRYPTO_BLOWFISH_BLOCKSIZE;
+ length -= MBEDCRYPTO_BLOWFISH_BLOCKSIZE;
+ }
+ }
+ else
+ {
+ while( length > 0 )
+ {
+ for( i = 0; i < MBEDCRYPTO_BLOWFISH_BLOCKSIZE; i++ )
+ output[i] = (unsigned char)( input[i] ^ iv[i] );
+
+ mbedcrypto_blowfish_crypt_ecb( ctx, mode, output, output );
+ memcpy( iv, output, MBEDCRYPTO_BLOWFISH_BLOCKSIZE );
+
+ input += MBEDCRYPTO_BLOWFISH_BLOCKSIZE;
+ output += MBEDCRYPTO_BLOWFISH_BLOCKSIZE;
+ length -= MBEDCRYPTO_BLOWFISH_BLOCKSIZE;
+ }
+ }
+
+ return( 0 );
+}
+#endif /* MBEDCRYPTO_CIPHER_MODE_CBC */
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CFB)
+/*
+ * Blowfish CFB buffer encryption/decryption
+ */
+int mbedcrypto_blowfish_crypt_cfb64( mbedcrypto_blowfish_context *ctx,
+ int mode,
+ size_t length,
+ size_t *iv_off,
+ unsigned char iv[MBEDCRYPTO_BLOWFISH_BLOCKSIZE],
+ const unsigned char *input,
+ unsigned char *output )
+{
+ int c;
+ size_t n = *iv_off;
+
+ if( mode == MBEDCRYPTO_BLOWFISH_DECRYPT )
+ {
+ while( length-- )
+ {
+ if( n == 0 )
+ mbedcrypto_blowfish_crypt_ecb( ctx, MBEDCRYPTO_BLOWFISH_ENCRYPT, iv, iv );
+
+ c = *input++;
+ *output++ = (unsigned char)( c ^ iv[n] );
+ iv[n] = (unsigned char) c;
+
+ n = ( n + 1 ) % MBEDCRYPTO_BLOWFISH_BLOCKSIZE;
+ }
+ }
+ else
+ {
+ while( length-- )
+ {
+ if( n == 0 )
+ mbedcrypto_blowfish_crypt_ecb( ctx, MBEDCRYPTO_BLOWFISH_ENCRYPT, iv, iv );
+
+ iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ );
+
+ n = ( n + 1 ) % MBEDCRYPTO_BLOWFISH_BLOCKSIZE;
+ }
+ }
+
+ *iv_off = n;
+
+ return( 0 );
+}
+#endif /*MBEDCRYPTO_CIPHER_MODE_CFB */
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CTR)
+/*
+ * Blowfish CTR buffer encryption/decryption
+ */
+int mbedcrypto_blowfish_crypt_ctr( mbedcrypto_blowfish_context *ctx,
+ size_t length,
+ size_t *nc_off,
+ unsigned char nonce_counter[MBEDCRYPTO_BLOWFISH_BLOCKSIZE],
+ unsigned char stream_block[MBEDCRYPTO_BLOWFISH_BLOCKSIZE],
+ const unsigned char *input,
+ unsigned char *output )
+{
+ int c, i;
+ size_t n = *nc_off;
+
+ while( length-- )
+ {
+ if( n == 0 ) {
+ mbedcrypto_blowfish_crypt_ecb( ctx, MBEDCRYPTO_BLOWFISH_ENCRYPT, nonce_counter,
+ stream_block );
+
+ for( i = MBEDCRYPTO_BLOWFISH_BLOCKSIZE; i > 0; i-- )
+ if( ++nonce_counter[i - 1] != 0 )
+ break;
+ }
+ c = *input++;
+ *output++ = (unsigned char)( c ^ stream_block[n] );
+
+ n = ( n + 1 ) % MBEDCRYPTO_BLOWFISH_BLOCKSIZE;
+ }
+
+ *nc_off = n;
+
+ return( 0 );
+}
+#endif /* MBEDCRYPTO_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 /* !MBEDCRYPTO_BLOWFISH_ALT */
+#endif /* MBEDCRYPTO_BLOWFISH_C */
diff --git a/library/camellia.c b/library/camellia.c
new file mode 100644
index 0000000..a5361fd
--- /dev/null
+++ b/library/camellia.c
@@ -0,0 +1,1068 @@
+/*
+ * 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 Crypto (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(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_CAMELLIA_C)
+
+#include "mbedcrypto/camellia.h"
+#include "mbedcrypto/platform_util.h"
+
+#include <string.h>
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#include <stdio.h>
+#define mbedcrypto_printf printf
+#endif /* MBEDCRYPTO_PLATFORM_C */
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#if !defined(MBEDCRYPTO_CAMELLIA_ALT)
+
+/*
+ * 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(MBEDCRYPTO_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 /* MBEDCRYPTO_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 /* MBEDCRYPTO_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 mbedcrypto_camellia_init( mbedcrypto_camellia_context *ctx )
+{
+ memset( ctx, 0, sizeof( mbedcrypto_camellia_context ) );
+}
+
+void mbedcrypto_camellia_free( mbedcrypto_camellia_context *ctx )
+{
+ if( ctx == NULL )
+ return;
+
+ mbedcrypto_platform_zeroize( ctx, sizeof( mbedcrypto_camellia_context ) );
+}
+
+/*
+ * Camellia key schedule (encryption)
+ */
+int mbedcrypto_camellia_setkey_enc( mbedcrypto_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( MBEDCRYPTO_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 mbedcrypto_camellia_setkey_dec( mbedcrypto_camellia_context *ctx, const unsigned char *key,
+ unsigned int keybits )
+{
+ int idx, ret;
+ size_t i;
+ mbedcrypto_camellia_context cty;
+ uint32_t *RK;
+ uint32_t *SK;
+
+ mbedcrypto_camellia_init( &cty );
+
+ /* Also checks keybits */
+ if( ( ret = mbedcrypto_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:
+ mbedcrypto_camellia_free( &cty );
+
+ return( ret );
+}
+
+/*
+ * Camellia-ECB block encryption/decryption
+ */
+int mbedcrypto_camellia_crypt_ecb( mbedcrypto_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(MBEDCRYPTO_CIPHER_MODE_CBC)
+/*
+ * Camellia-CBC buffer encryption/decryption
+ */
+int mbedcrypto_camellia_crypt_cbc( mbedcrypto_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( MBEDCRYPTO_ERR_CAMELLIA_INVALID_INPUT_LENGTH );
+
+ if( mode == MBEDCRYPTO_CAMELLIA_DECRYPT )
+ {
+ while( length > 0 )
+ {
+ memcpy( temp, input, 16 );
+ mbedcrypto_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] );
+
+ mbedcrypto_camellia_crypt_ecb( ctx, mode, output, output );
+ memcpy( iv, output, 16 );
+
+ input += 16;
+ output += 16;
+ length -= 16;
+ }
+ }
+
+ return( 0 );
+}
+#endif /* MBEDCRYPTO_CIPHER_MODE_CBC */
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CFB)
+/*
+ * Camellia-CFB128 buffer encryption/decryption
+ */
+int mbedcrypto_camellia_crypt_cfb128( mbedcrypto_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 == MBEDCRYPTO_CAMELLIA_DECRYPT )
+ {
+ while( length-- )
+ {
+ if( n == 0 )
+ mbedcrypto_camellia_crypt_ecb( ctx, MBEDCRYPTO_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 )
+ mbedcrypto_camellia_crypt_ecb( ctx, MBEDCRYPTO_CAMELLIA_ENCRYPT, iv, iv );
+
+ iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ );
+
+ n = ( n + 1 ) & 0x0F;
+ }
+ }
+
+ *iv_off = n;
+
+ return( 0 );
+}
+#endif /* MBEDCRYPTO_CIPHER_MODE_CFB */
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CTR)
+/*
+ * Camellia-CTR buffer encryption/decryption
+ */
+int mbedcrypto_camellia_crypt_ctr( mbedcrypto_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 ) {
+ mbedcrypto_camellia_crypt_ecb( ctx, MBEDCRYPTO_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 /* MBEDCRYPTO_CIPHER_MODE_CTR */
+#endif /* !MBEDCRYPTO_CAMELLIA_ALT */
+
+#if defined(MBEDCRYPTO_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(MBEDCRYPTO_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 /* MBEDCRYPTO_CIPHER_MODE_CBC */
+
+#if defined(MBEDCRYPTO_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 /* MBEDCRYPTO_CIPHER_MODE_CTR */
+
+/*
+ * Checkup routine
+ */
+int mbedcrypto_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(MBEDCRYPTO_CIPHER_MODE_CBC)
+ unsigned char iv[16];
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CTR)
+ size_t offset, len;
+ unsigned char nonce_counter[16];
+ unsigned char stream_block[16];
+#endif
+
+ mbedcrypto_camellia_context ctx;
+
+ memset( key, 0, 32 );
+
+ for( j = 0; j < 6; j++ ) {
+ u = j >> 1;
+ v = j & 1;
+
+ if( verbose != 0 )
+ mbedcrypto_printf( " CAMELLIA-ECB-%3d (%s): ", 128 + u * 64,
+ (v == MBEDCRYPTO_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 == MBEDCRYPTO_CAMELLIA_DECRYPT ) {
+ mbedcrypto_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 { /* MBEDCRYPTO_CAMELLIA_ENCRYPT */
+ mbedcrypto_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 );
+ }
+
+ mbedcrypto_camellia_crypt_ecb( &ctx, v, src, buf );
+
+ if( memcmp( buf, dst, 16 ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+
+ return( 1 );
+ }
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "\n" );
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+ /*
+ * CBC mode
+ */
+ for( j = 0; j < 6; j++ )
+ {
+ u = j >> 1;
+ v = j & 1;
+
+ if( verbose != 0 )
+ mbedcrypto_printf( " CAMELLIA-CBC-%3d (%s): ", 128 + u * 64,
+ ( v == MBEDCRYPTO_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 == MBEDCRYPTO_CAMELLIA_DECRYPT ) {
+ mbedcrypto_camellia_setkey_dec( &ctx, key, 128 + u * 64 );
+ } else {
+ mbedcrypto_camellia_setkey_enc( &ctx, key, 128 + u * 64 );
+ }
+
+ for( i = 0; i < CAMELLIA_TESTS_CBC; i++ ) {
+
+ if( v == MBEDCRYPTO_CAMELLIA_DECRYPT ) {
+ memcpy( iv , src, 16 );
+ memcpy( src, camellia_test_cbc_cipher[u][i], 16 );
+ memcpy( dst, camellia_test_cbc_plain[i], 16 );
+ } else { /* MBEDCRYPTO_CAMELLIA_ENCRYPT */
+ memcpy( iv , dst, 16 );
+ memcpy( src, camellia_test_cbc_plain[i], 16 );
+ memcpy( dst, camellia_test_cbc_cipher[u][i], 16 );
+ }
+
+ mbedcrypto_camellia_crypt_cbc( &ctx, v, 16, iv, src, buf );
+
+ if( memcmp( buf, dst, 16 ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+
+ return( 1 );
+ }
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+ }
+#endif /* MBEDCRYPTO_CIPHER_MODE_CBC */
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "\n" );
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CTR)
+ /*
+ * CTR mode
+ */
+ for( i = 0; i < 6; i++ )
+ {
+ u = i >> 1;
+ v = i & 1;
+
+ if( verbose != 0 )
+ mbedcrypto_printf( " CAMELLIA-CTR-128 (%s): ",
+ ( v == MBEDCRYPTO_CAMELLIA_DECRYPT ) ? "dec" : "enc" );
+
+ memcpy( nonce_counter, camellia_test_ctr_nonce_counter[u], 16 );
+ memcpy( key, camellia_test_ctr_key[u], 16 );
+
+ offset = 0;
+ mbedcrypto_camellia_setkey_enc( &ctx, key, 128 );
+
+ if( v == MBEDCRYPTO_CAMELLIA_DECRYPT )
+ {
+ len = camellia_test_ctr_len[u];
+ memcpy( buf, camellia_test_ctr_ct[u], len );
+
+ mbedcrypto_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 )
+ mbedcrypto_printf( "failed\n" );
+
+ return( 1 );
+ }
+ }
+ else
+ {
+ len = camellia_test_ctr_len[u];
+ memcpy( buf, camellia_test_ctr_pt[u], len );
+
+ mbedcrypto_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 )
+ mbedcrypto_printf( "failed\n" );
+
+ return( 1 );
+ }
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "\n" );
+#endif /* MBEDCRYPTO_CIPHER_MODE_CTR */
+
+ return( 0 );
+}
+
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#endif /* MBEDCRYPTO_CAMELLIA_C */
diff --git a/library/ccm.c b/library/ccm.c
new file mode 100644
index 0000000..d39387f
--- /dev/null
+++ b/library/ccm.c
@@ -0,0 +1,463 @@
+/*
+ * 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 Crypto (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(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_CCM_C)
+
+#include "mbedcrypto/ccm.h"
+#include "mbedcrypto/platform_util.h"
+
+#include <string.h>
+
+#if defined(MBEDCRYPTO_SELF_TEST) && defined(MBEDCRYPTO_AES_C)
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#include <stdio.h>
+#define mbedcrypto_printf printf
+#endif /* MBEDCRYPTO_PLATFORM_C */
+#endif /* MBEDCRYPTO_SELF_TEST && MBEDCRYPTO_AES_C */
+
+#if !defined(MBEDCRYPTO_CCM_ALT)
+
+#define CCM_ENCRYPT 0
+#define CCM_DECRYPT 1
+
+/*
+ * Initialize context
+ */
+void mbedcrypto_ccm_init( mbedcrypto_ccm_context *ctx )
+{
+ memset( ctx, 0, sizeof( mbedcrypto_ccm_context ) );
+}
+
+int mbedcrypto_ccm_setkey( mbedcrypto_ccm_context *ctx,
+ mbedcrypto_cipher_id_t cipher,
+ const unsigned char *key,
+ unsigned int keybits )
+{
+ int ret;
+ const mbedcrypto_cipher_info_t *cipher_info;
+
+ cipher_info = mbedcrypto_cipher_info_from_values( cipher, keybits, MBEDCRYPTO_MODE_ECB );
+ if( cipher_info == NULL )
+ return( MBEDCRYPTO_ERR_CCM_BAD_INPUT );
+
+ if( cipher_info->block_size != 16 )
+ return( MBEDCRYPTO_ERR_CCM_BAD_INPUT );
+
+ mbedcrypto_cipher_free( &ctx->cipher_ctx );
+
+ if( ( ret = mbedcrypto_cipher_setup( &ctx->cipher_ctx, cipher_info ) ) != 0 )
+ return( ret );
+
+ if( ( ret = mbedcrypto_cipher_setkey( &ctx->cipher_ctx, key, keybits,
+ MBEDCRYPTO_ENCRYPT ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ return( 0 );
+}
+
+/*
+ * Free context
+ */
+void mbedcrypto_ccm_free( mbedcrypto_ccm_context *ctx )
+{
+ mbedcrypto_cipher_free( &ctx->cipher_ctx );
+ mbedcrypto_platform_zeroize( ctx, sizeof( mbedcrypto_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 = mbedcrypto_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 = mbedcrypto_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( mbedcrypto_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( MBEDCRYPTO_ERR_CCM_BAD_INPUT );
+
+ /* Also implies q is within bounds */
+ if( iv_len < 7 || iv_len > 13 )
+ return( MBEDCRYPTO_ERR_CCM_BAD_INPUT );
+
+ if( add_len > 0xFF00 )
+ return( MBEDCRYPTO_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( MBEDCRYPTO_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 mbedcrypto_ccm_encrypt_and_tag( mbedcrypto_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 mbedcrypto_ccm_auth_decrypt( mbedcrypto_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 )
+ {
+ mbedcrypto_platform_zeroize( output, length );
+ return( MBEDCRYPTO_ERR_CCM_AUTH_FAILED );
+ }
+
+ return( 0 );
+}
+
+#endif /* !MBEDCRYPTO_CCM_ALT */
+
+#if defined(MBEDCRYPTO_SELF_TEST) && defined(MBEDCRYPTO_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 mbedcrypto_ccm_self_test( int verbose )
+{
+ mbedcrypto_ccm_context ctx;
+ unsigned char out[32];
+ size_t i;
+ int ret;
+
+ mbedcrypto_ccm_init( &ctx );
+
+ if( mbedcrypto_ccm_setkey( &ctx, MBEDCRYPTO_CIPHER_ID_AES, key, 8 * sizeof key ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( " CCM: setup failed" );
+
+ return( 1 );
+ }
+
+ for( i = 0; i < NB_TESTS; i++ )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( " CCM-AES #%u: ", (unsigned int) i + 1 );
+
+ ret = mbedcrypto_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 )
+ mbedcrypto_printf( "failed\n" );
+
+ return( 1 );
+ }
+
+ ret = mbedcrypto_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 )
+ mbedcrypto_printf( "failed\n" );
+
+ return( 1 );
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+ }
+
+ mbedcrypto_ccm_free( &ctx );
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "\n" );
+
+ return( 0 );
+}
+
+#endif /* MBEDCRYPTO_SELF_TEST && MBEDCRYPTO_AES_C */
+
+#endif /* MBEDCRYPTO_CCM_C */
diff --git a/library/cipher.c b/library/cipher.c
new file mode 100644
index 0000000..61ee930
--- /dev/null
+++ b/library/cipher.c
@@ -0,0 +1,924 @@
+/**
+ * \file cipher.c
+ *
+ * \brief Generic cipher wrapper for Mbed Crypto
+ *
+ * \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 Crypto (https://tls.mbed.org)
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_CIPHER_C)
+
+#include "mbedcrypto/cipher.h"
+#include "mbedcrypto/cipher_internal.h"
+#include "mbedcrypto/platform_util.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(MBEDCRYPTO_GCM_C)
+#include "mbedcrypto/gcm.h"
+#endif
+
+#if defined(MBEDCRYPTO_CCM_C)
+#include "mbedcrypto/ccm.h"
+#endif
+
+#if defined(MBEDCRYPTO_CMAC_C)
+#include "mbedcrypto/cmac.h"
+#endif
+
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#define mbedcrypto_calloc calloc
+#define mbedcrypto_free free
+#endif
+
+#if defined(MBEDCRYPTO_ARC4_C) || defined(MBEDCRYPTO_CIPHER_NULL_CIPHER)
+#define MBEDCRYPTO_CIPHER_MODE_STREAM
+#endif
+
+static int supported_init = 0;
+
+const int *mbedcrypto_cipher_list( void )
+{
+ const mbedcrypto_cipher_definition_t *def;
+ int *type;
+
+ if( ! supported_init )
+ {
+ def = mbedcrypto_cipher_definitions;
+ type = mbedcrypto_cipher_supported;
+
+ while( def->type != 0 )
+ *type++ = (*def++).type;
+
+ *type = 0;
+
+ supported_init = 1;
+ }
+
+ return( mbedcrypto_cipher_supported );
+}
+
+const mbedcrypto_cipher_info_t *mbedcrypto_cipher_info_from_type( const mbedcrypto_cipher_type_t cipher_type )
+{
+ const mbedcrypto_cipher_definition_t *def;
+
+ for( def = mbedcrypto_cipher_definitions; def->info != NULL; def++ )
+ if( def->type == cipher_type )
+ return( def->info );
+
+ return( NULL );
+}
+
+const mbedcrypto_cipher_info_t *mbedcrypto_cipher_info_from_string( const char *cipher_name )
+{
+ const mbedcrypto_cipher_definition_t *def;
+
+ if( NULL == cipher_name )
+ return( NULL );
+
+ for( def = mbedcrypto_cipher_definitions; def->info != NULL; def++ )
+ if( ! strcmp( def->info->name, cipher_name ) )
+ return( def->info );
+
+ return( NULL );
+}
+
+const mbedcrypto_cipher_info_t *mbedcrypto_cipher_info_from_values( const mbedcrypto_cipher_id_t cipher_id,
+ int key_bitlen,
+ const mbedcrypto_cipher_mode_t mode )
+{
+ const mbedcrypto_cipher_definition_t *def;
+
+ for( def = mbedcrypto_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 mbedcrypto_cipher_init( mbedcrypto_cipher_context_t *ctx )
+{
+ memset( ctx, 0, sizeof( mbedcrypto_cipher_context_t ) );
+}
+
+void mbedcrypto_cipher_free( mbedcrypto_cipher_context_t *ctx )
+{
+ if( ctx == NULL )
+ return;
+
+#if defined(MBEDCRYPTO_CMAC_C)
+ if( ctx->cmac_ctx )
+ {
+ mbedcrypto_platform_zeroize( ctx->cmac_ctx,
+ sizeof( mbedcrypto_cmac_context_t ) );
+ mbedcrypto_free( ctx->cmac_ctx );
+ }
+#endif
+
+ if( ctx->cipher_ctx )
+ ctx->cipher_info->base->ctx_free_func( ctx->cipher_ctx );
+
+ mbedcrypto_platform_zeroize( ctx, sizeof(mbedcrypto_cipher_context_t) );
+}
+
+int mbedcrypto_cipher_setup( mbedcrypto_cipher_context_t *ctx, const mbedcrypto_cipher_info_t *cipher_info )
+{
+ if( NULL == cipher_info || NULL == ctx )
+ return( MBEDCRYPTO_ERR_CIPHER_BAD_INPUT_DATA );
+
+ memset( ctx, 0, sizeof( mbedcrypto_cipher_context_t ) );
+
+ if( NULL == ( ctx->cipher_ctx = cipher_info->base->ctx_alloc_func() ) )
+ return( MBEDCRYPTO_ERR_CIPHER_ALLOC_FAILED );
+
+ ctx->cipher_info = cipher_info;
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_WITH_PADDING)
+ /*
+ * Ignore possible errors caused by a cipher mode that doesn't use padding
+ */
+#if defined(MBEDCRYPTO_CIPHER_PADDING_PKCS7)
+ (void) mbedcrypto_cipher_set_padding_mode( ctx, MBEDCRYPTO_PADDING_PKCS7 );
+#else
+ (void) mbedcrypto_cipher_set_padding_mode( ctx, MBEDCRYPTO_PADDING_NONE );
+#endif
+#endif /* MBEDCRYPTO_CIPHER_MODE_WITH_PADDING */
+
+ return( 0 );
+}
+
+int mbedcrypto_cipher_setkey( mbedcrypto_cipher_context_t *ctx, const unsigned char *key,
+ int key_bitlen, const mbedcrypto_operation_t operation )
+{
+ if( NULL == ctx || NULL == ctx->cipher_info )
+ return( MBEDCRYPTO_ERR_CIPHER_BAD_INPUT_DATA );
+
+ if( ( ctx->cipher_info->flags & MBEDCRYPTO_CIPHER_VARIABLE_KEY_LEN ) == 0 &&
+ (int) ctx->cipher_info->key_bitlen != key_bitlen )
+ {
+ return( MBEDCRYPTO_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( MBEDCRYPTO_ENCRYPT == operation ||
+ MBEDCRYPTO_MODE_CFB == ctx->cipher_info->mode ||
+ MBEDCRYPTO_MODE_CTR == ctx->cipher_info->mode )
+ {
+ return ctx->cipher_info->base->setkey_enc_func( ctx->cipher_ctx, key,
+ ctx->key_bitlen );
+ }
+
+ if( MBEDCRYPTO_DECRYPT == operation )
+ return ctx->cipher_info->base->setkey_dec_func( ctx->cipher_ctx, key,
+ ctx->key_bitlen );
+
+ return( MBEDCRYPTO_ERR_CIPHER_BAD_INPUT_DATA );
+}
+
+int mbedcrypto_cipher_set_iv( mbedcrypto_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( MBEDCRYPTO_ERR_CIPHER_BAD_INPUT_DATA );
+
+ /* avoid buffer overflow in ctx->iv */
+ if( iv_len > MBEDCRYPTO_MAX_IV_LENGTH )
+ return( MBEDCRYPTO_ERR_CIPHER_FEATURE_UNAVAILABLE );
+
+ if( ( ctx->cipher_info->flags & MBEDCRYPTO_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( MBEDCRYPTO_ERR_CIPHER_BAD_INPUT_DATA );
+ }
+
+ memcpy( ctx->iv, iv, actual_iv_size );
+ ctx->iv_size = actual_iv_size;
+
+ return( 0 );
+}
+
+int mbedcrypto_cipher_reset( mbedcrypto_cipher_context_t *ctx )
+{
+ if( NULL == ctx || NULL == ctx->cipher_info )
+ return( MBEDCRYPTO_ERR_CIPHER_BAD_INPUT_DATA );
+
+ ctx->unprocessed_len = 0;
+
+ return( 0 );
+}
+
+#if defined(MBEDCRYPTO_GCM_C)
+int mbedcrypto_cipher_update_ad( mbedcrypto_cipher_context_t *ctx,
+ const unsigned char *ad, size_t ad_len )
+{
+ if( NULL == ctx || NULL == ctx->cipher_info )
+ return( MBEDCRYPTO_ERR_CIPHER_BAD_INPUT_DATA );
+
+ if( MBEDCRYPTO_MODE_GCM == ctx->cipher_info->mode )
+ {
+ return mbedcrypto_gcm_starts( (mbedcrypto_gcm_context *) ctx->cipher_ctx, ctx->operation,
+ ctx->iv, ctx->iv_size, ad, ad_len );
+ }
+
+ return( 0 );
+}
+#endif /* MBEDCRYPTO_GCM_C */
+
+int mbedcrypto_cipher_update( mbedcrypto_cipher_context_t *ctx, const unsigned char *input,
+ size_t ilen, unsigned char *output, size_t *olen )
+{
+ int ret;
+ size_t block_size = 0;
+
+ if( NULL == ctx || NULL == ctx->cipher_info || NULL == olen )
+ {
+ return( MBEDCRYPTO_ERR_CIPHER_BAD_INPUT_DATA );
+ }
+
+ *olen = 0;
+ block_size = mbedcrypto_cipher_get_block_size( ctx );
+
+ if( ctx->cipher_info->mode == MBEDCRYPTO_MODE_ECB )
+ {
+ if( ilen != block_size )
+ return( MBEDCRYPTO_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(MBEDCRYPTO_GCM_C)
+ if( ctx->cipher_info->mode == MBEDCRYPTO_MODE_GCM )
+ {
+ *olen = ilen;
+ return mbedcrypto_gcm_update( (mbedcrypto_gcm_context *) ctx->cipher_ctx, ilen, input,
+ output );
+ }
+#endif
+
+ if ( 0 == block_size )
+ {
+ return MBEDCRYPTO_ERR_CIPHER_INVALID_CONTEXT;
+ }
+
+ if( input == output &&
+ ( ctx->unprocessed_len != 0 || ilen % block_size ) )
+ {
+ return( MBEDCRYPTO_ERR_CIPHER_BAD_INPUT_DATA );
+ }
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+ if( ctx->cipher_info->mode == MBEDCRYPTO_MODE_CBC )
+ {
+ size_t copy_len = 0;
+
+ /*
+ * If there is not enough data for a full block, cache it.
+ */
+ if( ( ctx->operation == MBEDCRYPTO_DECRYPT && NULL != ctx->add_padding &&
+ ilen <= block_size - ctx->unprocessed_len ) ||
+ ( ctx->operation == MBEDCRYPTO_DECRYPT && NULL == ctx->add_padding &&
+ ilen < block_size - ctx->unprocessed_len ) ||
+ ( ctx->operation == MBEDCRYPTO_ENCRYPT &&
+ ilen < block_size - ctx->unprocessed_len ) )
+ {
+ memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ), input,
+ ilen );
+
+ ctx->unprocessed_len += ilen;
+ return( 0 );
+ }
+
+ /*
+ * Process cached data first
+ */
+ if( 0 != ctx->unprocessed_len )
+ {
+ copy_len = block_size - 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, block_size, ctx->iv,
+ ctx->unprocessed_data, output ) ) )
+ {
+ return( ret );
+ }
+
+ *olen += block_size;
+ output += block_size;
+ ctx->unprocessed_len = 0;
+
+ input += copy_len;
+ ilen -= copy_len;
+ }
+
+ /*
+ * Cache final, incomplete block
+ */
+ if( 0 != ilen )
+ {
+ if( 0 == block_size )
+ {
+ return MBEDCRYPTO_ERR_CIPHER_INVALID_CONTEXT;
+ }
+
+ /* Encryption: only cache partial blocks
+ * Decryption w/ padding: always keep at least one whole block
+ * Decryption w/o padding: only cache partial blocks
+ */
+ copy_len = ilen % block_size;
+ if( copy_len == 0 &&
+ ctx->operation == MBEDCRYPTO_DECRYPT &&
+ NULL != ctx->add_padding)
+ {
+ copy_len = block_size;
+ }
+
+ 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 /* MBEDCRYPTO_CIPHER_MODE_CBC */
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CFB)
+ if( ctx->cipher_info->mode == MBEDCRYPTO_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 /* MBEDCRYPTO_CIPHER_MODE_CFB */
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CTR)
+ if( ctx->cipher_info->mode == MBEDCRYPTO_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 /* MBEDCRYPTO_CIPHER_MODE_CTR */
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_STREAM)
+ if( ctx->cipher_info->mode == MBEDCRYPTO_MODE_STREAM )
+ {
+ if( 0 != ( ret = ctx->cipher_info->base->stream_func( ctx->cipher_ctx,
+ ilen, input, output ) ) )
+ {
+ return( ret );
+ }
+
+ *olen = ilen;
+
+ return( 0 );
+ }
+#endif /* MBEDCRYPTO_CIPHER_MODE_STREAM */
+
+ return( MBEDCRYPTO_ERR_CIPHER_FEATURE_UNAVAILABLE );
+}
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_WITH_PADDING)
+#if defined(MBEDCRYPTO_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( MBEDCRYPTO_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( MBEDCRYPTO_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) );
+}
+#endif /* MBEDCRYPTO_CIPHER_PADDING_PKCS7 */
+
+#if defined(MBEDCRYPTO_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( MBEDCRYPTO_ERR_CIPHER_BAD_INPUT_DATA );
+
+ bad = 0x80;
+ *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] * ( done != prev_done );
+ }
+
+ return( MBEDCRYPTO_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) );
+
+}
+#endif /* MBEDCRYPTO_CIPHER_PADDING_ONE_AND_ZEROS */
+
+#if defined(MBEDCRYPTO_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( MBEDCRYPTO_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( MBEDCRYPTO_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) );
+}
+#endif /* MBEDCRYPTO_CIPHER_PADDING_ZEROS_AND_LEN */
+
+#if defined(MBEDCRYPTO_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( MBEDCRYPTO_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 /* MBEDCRYPTO_CIPHER_PADDING_ZEROS */
+
+/*
+ * No padding: don't pad :)
+ *
+ * There is no add_padding function (check for NULL in mbedcrypto_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( MBEDCRYPTO_ERR_CIPHER_BAD_INPUT_DATA );
+
+ *data_len = input_len;
+
+ return( 0 );
+}
+#endif /* MBEDCRYPTO_CIPHER_MODE_WITH_PADDING */
+
+int mbedcrypto_cipher_finish( mbedcrypto_cipher_context_t *ctx,
+ unsigned char *output, size_t *olen )
+{
+ if( NULL == ctx || NULL == ctx->cipher_info || NULL == olen )
+ return( MBEDCRYPTO_ERR_CIPHER_BAD_INPUT_DATA );
+
+ *olen = 0;
+
+ if( MBEDCRYPTO_MODE_CFB == ctx->cipher_info->mode ||
+ MBEDCRYPTO_MODE_CTR == ctx->cipher_info->mode ||
+ MBEDCRYPTO_MODE_GCM == ctx->cipher_info->mode ||
+ MBEDCRYPTO_MODE_STREAM == ctx->cipher_info->mode )
+ {
+ return( 0 );
+ }
+
+ if( MBEDCRYPTO_MODE_ECB == ctx->cipher_info->mode )
+ {
+ if( ctx->unprocessed_len != 0 )
+ return( MBEDCRYPTO_ERR_CIPHER_FULL_BLOCK_EXPECTED );
+
+ return( 0 );
+ }
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+ if( MBEDCRYPTO_MODE_CBC == ctx->cipher_info->mode )
+ {
+ int ret = 0;
+
+ if( MBEDCRYPTO_ENCRYPT == ctx->operation )
+ {
+ /* check for 'no padding' mode */
+ if( NULL == ctx->add_padding )
+ {
+ if( 0 != ctx->unprocessed_len )
+ return( MBEDCRYPTO_ERR_CIPHER_FULL_BLOCK_EXPECTED );
+
+ return( 0 );
+ }
+
+ ctx->add_padding( ctx->unprocessed_data, mbedcrypto_cipher_get_iv_size( ctx ),
+ ctx->unprocessed_len );
+ }
+ else if( mbedcrypto_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( MBEDCRYPTO_ERR_CIPHER_FULL_BLOCK_EXPECTED );
+ }
+
+ /* cipher block */
+ if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx,
+ ctx->operation, mbedcrypto_cipher_get_block_size( ctx ), ctx->iv,
+ ctx->unprocessed_data, output ) ) )
+ {
+ return( ret );
+ }
+
+ /* Set output size for decryption */
+ if( MBEDCRYPTO_DECRYPT == ctx->operation )
+ return ctx->get_padding( output, mbedcrypto_cipher_get_block_size( ctx ),
+ olen );
+
+ /* Set output size for encryption */
+ *olen = mbedcrypto_cipher_get_block_size( ctx );
+ return( 0 );
+ }
+#else
+ ((void) output);
+#endif /* MBEDCRYPTO_CIPHER_MODE_CBC */
+
+ return( MBEDCRYPTO_ERR_CIPHER_FEATURE_UNAVAILABLE );
+}
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_WITH_PADDING)
+int mbedcrypto_cipher_set_padding_mode( mbedcrypto_cipher_context_t *ctx, mbedcrypto_cipher_padding_t mode )
+{
+ if( NULL == ctx ||
+ MBEDCRYPTO_MODE_CBC != ctx->cipher_info->mode )
+ {
+ return( MBEDCRYPTO_ERR_CIPHER_BAD_INPUT_DATA );
+ }
+
+ switch( mode )
+ {
+#if defined(MBEDCRYPTO_CIPHER_PADDING_PKCS7)
+ case MBEDCRYPTO_PADDING_PKCS7:
+ ctx->add_padding = add_pkcs_padding;
+ ctx->get_padding = get_pkcs_padding;
+ break;
+#endif
+#if defined(MBEDCRYPTO_CIPHER_PADDING_ONE_AND_ZEROS)
+ case MBEDCRYPTO_PADDING_ONE_AND_ZEROS:
+ ctx->add_padding = add_one_and_zeros_padding;
+ ctx->get_padding = get_one_and_zeros_padding;
+ break;
+#endif
+#if defined(MBEDCRYPTO_CIPHER_PADDING_ZEROS_AND_LEN)
+ case MBEDCRYPTO_PADDING_ZEROS_AND_LEN:
+ ctx->add_padding = add_zeros_and_len_padding;
+ ctx->get_padding = get_zeros_and_len_padding;
+ break;
+#endif
+#if defined(MBEDCRYPTO_CIPHER_PADDING_ZEROS)
+ case MBEDCRYPTO_PADDING_ZEROS:
+ ctx->add_padding = add_zeros_padding;
+ ctx->get_padding = get_zeros_padding;
+ break;
+#endif
+ case MBEDCRYPTO_PADDING_NONE:
+ ctx->add_padding = NULL;
+ ctx->get_padding = get_no_padding;
+ break;
+
+ default:
+ return( MBEDCRYPTO_ERR_CIPHER_FEATURE_UNAVAILABLE );
+ }
+
+ return( 0 );
+}
+#endif /* MBEDCRYPTO_CIPHER_MODE_WITH_PADDING */
+
+#if defined(MBEDCRYPTO_GCM_C)
+int mbedcrypto_cipher_write_tag( mbedcrypto_cipher_context_t *ctx,
+ unsigned char *tag, size_t tag_len )
+{
+ if( NULL == ctx || NULL == ctx->cipher_info || NULL == tag )
+ return( MBEDCRYPTO_ERR_CIPHER_BAD_INPUT_DATA );
+
+ if( MBEDCRYPTO_ENCRYPT != ctx->operation )
+ return( MBEDCRYPTO_ERR_CIPHER_BAD_INPUT_DATA );
+
+ if( MBEDCRYPTO_MODE_GCM == ctx->cipher_info->mode )
+ return mbedcrypto_gcm_finish( (mbedcrypto_gcm_context *) ctx->cipher_ctx, tag, tag_len );
+
+ return( 0 );
+}
+
+int mbedcrypto_cipher_check_tag( mbedcrypto_cipher_context_t *ctx,
+ const unsigned char *tag, size_t tag_len )
+{
+ int ret;
+
+ if( NULL == ctx || NULL == ctx->cipher_info ||
+ MBEDCRYPTO_DECRYPT != ctx->operation )
+ {
+ return( MBEDCRYPTO_ERR_CIPHER_BAD_INPUT_DATA );
+ }
+
+ if( MBEDCRYPTO_MODE_GCM == ctx->cipher_info->mode )
+ {
+ unsigned char check_tag[16];
+ size_t i;
+ int diff;
+
+ if( tag_len > sizeof( check_tag ) )
+ return( MBEDCRYPTO_ERR_CIPHER_BAD_INPUT_DATA );
+
+ if( 0 != ( ret = mbedcrypto_gcm_finish( (mbedcrypto_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( MBEDCRYPTO_ERR_CIPHER_AUTH_FAILED );
+
+ return( 0 );
+ }
+
+ return( 0 );
+}
+#endif /* MBEDCRYPTO_GCM_C */
+
+/*
+ * Packet-oriented wrapper for non-AEAD modes
+ */
+int mbedcrypto_cipher_crypt( mbedcrypto_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 = mbedcrypto_cipher_set_iv( ctx, iv, iv_len ) ) != 0 )
+ return( ret );
+
+ if( ( ret = mbedcrypto_cipher_reset( ctx ) ) != 0 )
+ return( ret );
+
+ if( ( ret = mbedcrypto_cipher_update( ctx, input, ilen, output, olen ) ) != 0 )
+ return( ret );
+
+ if( ( ret = mbedcrypto_cipher_finish( ctx, output + *olen, &finish_olen ) ) != 0 )
+ return( ret );
+
+ *olen += finish_olen;
+
+ return( 0 );
+}
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_AEAD)
+/*
+ * Packet-oriented encryption for AEAD modes
+ */
+int mbedcrypto_cipher_auth_encrypt( mbedcrypto_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(MBEDCRYPTO_GCM_C)
+ if( MBEDCRYPTO_MODE_GCM == ctx->cipher_info->mode )
+ {
+ *olen = ilen;
+ return( mbedcrypto_gcm_crypt_and_tag( ctx->cipher_ctx, MBEDCRYPTO_GCM_ENCRYPT, ilen,
+ iv, iv_len, ad, ad_len, input, output,
+ tag_len, tag ) );
+ }
+#endif /* MBEDCRYPTO_GCM_C */
+#if defined(MBEDCRYPTO_CCM_C)
+ if( MBEDCRYPTO_MODE_CCM == ctx->cipher_info->mode )
+ {
+ *olen = ilen;
+ return( mbedcrypto_ccm_encrypt_and_tag( ctx->cipher_ctx, ilen,
+ iv, iv_len, ad, ad_len, input, output,
+ tag, tag_len ) );
+ }
+#endif /* MBEDCRYPTO_CCM_C */
+
+ return( MBEDCRYPTO_ERR_CIPHER_FEATURE_UNAVAILABLE );
+}
+
+/*
+ * Packet-oriented decryption for AEAD modes
+ */
+int mbedcrypto_cipher_auth_decrypt( mbedcrypto_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(MBEDCRYPTO_GCM_C)
+ if( MBEDCRYPTO_MODE_GCM == ctx->cipher_info->mode )
+ {
+ int ret;
+
+ *olen = ilen;
+ ret = mbedcrypto_gcm_auth_decrypt( ctx->cipher_ctx, ilen,
+ iv, iv_len, ad, ad_len,
+ tag, tag_len, input, output );
+
+ if( ret == MBEDCRYPTO_ERR_GCM_AUTH_FAILED )
+ ret = MBEDCRYPTO_ERR_CIPHER_AUTH_FAILED;
+
+ return( ret );
+ }
+#endif /* MBEDCRYPTO_GCM_C */
+#if defined(MBEDCRYPTO_CCM_C)
+ if( MBEDCRYPTO_MODE_CCM == ctx->cipher_info->mode )
+ {
+ int ret;
+
+ *olen = ilen;
+ ret = mbedcrypto_ccm_auth_decrypt( ctx->cipher_ctx, ilen,
+ iv, iv_len, ad, ad_len,
+ input, output, tag, tag_len );
+
+ if( ret == MBEDCRYPTO_ERR_CCM_AUTH_FAILED )
+ ret = MBEDCRYPTO_ERR_CIPHER_AUTH_FAILED;
+
+ return( ret );
+ }
+#endif /* MBEDCRYPTO_CCM_C */
+
+ return( MBEDCRYPTO_ERR_CIPHER_FEATURE_UNAVAILABLE );
+}
+#endif /* MBEDCRYPTO_CIPHER_MODE_AEAD */
+
+#endif /* MBEDCRYPTO_CIPHER_C */
diff --git a/library/cipher_wrap.c b/library/cipher_wrap.c
new file mode 100644
index 0000000..0418b5f
--- /dev/null
+++ b/library/cipher_wrap.c
@@ -0,0 +1,1451 @@
+/**
+ * \file cipher_wrap.c
+ *
+ * \brief Generic cipher wrapper for Mbed Crypto
+ *
+ * \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 Crypto (https://tls.mbed.org)
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_CIPHER_C)
+
+#include "mbedcrypto/cipher_internal.h"
+
+#if defined(MBEDCRYPTO_AES_C)
+#include "mbedcrypto/aes.h"
+#endif
+
+#if defined(MBEDCRYPTO_ARC4_C)
+#include "mbedcrypto/arc4.h"
+#endif
+
+#if defined(MBEDCRYPTO_CAMELLIA_C)
+#include "mbedcrypto/camellia.h"
+#endif
+
+#if defined(MBEDCRYPTO_DES_C)
+#include "mbedcrypto/des.h"
+#endif
+
+#if defined(MBEDCRYPTO_BLOWFISH_C)
+#include "mbedcrypto/blowfish.h"
+#endif
+
+#if defined(MBEDCRYPTO_GCM_C)
+#include "mbedcrypto/gcm.h"
+#endif
+
+#if defined(MBEDCRYPTO_CCM_C)
+#include "mbedcrypto/ccm.h"
+#endif
+
+#if defined(MBEDCRYPTO_CIPHER_NULL_CIPHER)
+#include <string.h>
+#endif
+
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#include <stdlib.h>
+#define mbedcrypto_calloc calloc
+#define mbedcrypto_free free
+#endif
+
+#if defined(MBEDCRYPTO_GCM_C)
+/* shared by all GCM ciphers */
+static void *gcm_ctx_alloc( void )
+{
+ void *ctx = mbedcrypto_calloc( 1, sizeof( mbedcrypto_gcm_context ) );
+
+ if( ctx != NULL )
+ mbedcrypto_gcm_init( (mbedcrypto_gcm_context *) ctx );
+
+ return( ctx );
+}
+
+static void gcm_ctx_free( void *ctx )
+{
+ mbedcrypto_gcm_free( ctx );
+ mbedcrypto_free( ctx );
+}
+#endif /* MBEDCRYPTO_GCM_C */
+
+#if defined(MBEDCRYPTO_CCM_C)
+/* shared by all CCM ciphers */
+static void *ccm_ctx_alloc( void )
+{
+ void *ctx = mbedcrypto_calloc( 1, sizeof( mbedcrypto_ccm_context ) );
+
+ if( ctx != NULL )
+ mbedcrypto_ccm_init( (mbedcrypto_ccm_context *) ctx );
+
+ return( ctx );
+}
+
+static void ccm_ctx_free( void *ctx )
+{
+ mbedcrypto_ccm_free( ctx );
+ mbedcrypto_free( ctx );
+}
+#endif /* MBEDCRYPTO_CCM_C */
+
+#if defined(MBEDCRYPTO_AES_C)
+
+static int aes_crypt_ecb_wrap( void *ctx, mbedcrypto_operation_t operation,
+ const unsigned char *input, unsigned char *output )
+{
+ return mbedcrypto_aes_crypt_ecb( (mbedcrypto_aes_context *) ctx, operation, input, output );
+}
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+static int aes_crypt_cbc_wrap( void *ctx, mbedcrypto_operation_t operation, size_t length,
+ unsigned char *iv, const unsigned char *input, unsigned char *output )
+{
+ return mbedcrypto_aes_crypt_cbc( (mbedcrypto_aes_context *) ctx, operation, length, iv, input,
+ output );
+}
+#endif /* MBEDCRYPTO_CIPHER_MODE_CBC */
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CFB)
+static int aes_crypt_cfb128_wrap( void *ctx, mbedcrypto_operation_t operation,
+ size_t length, size_t *iv_off, unsigned char *iv,
+ const unsigned char *input, unsigned char *output )
+{
+ return mbedcrypto_aes_crypt_cfb128( (mbedcrypto_aes_context *) ctx, operation, length, iv_off, iv,
+ input, output );
+}
+#endif /* MBEDCRYPTO_CIPHER_MODE_CFB */
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CTR)
+static int aes_crypt_ctr_wrap( void *ctx, size_t length, size_t *nc_off,
+ unsigned char *nonce_counter, unsigned char *stream_block,
+ const unsigned char *input, unsigned char *output )
+{
+ return mbedcrypto_aes_crypt_ctr( (mbedcrypto_aes_context *) ctx, length, nc_off, nonce_counter,
+ stream_block, input, output );
+}
+#endif /* MBEDCRYPTO_CIPHER_MODE_CTR */
+
+static int aes_setkey_dec_wrap( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ return mbedcrypto_aes_setkey_dec( (mbedcrypto_aes_context *) ctx, key, key_bitlen );
+}
+
+static int aes_setkey_enc_wrap( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ return mbedcrypto_aes_setkey_enc( (mbedcrypto_aes_context *) ctx, key, key_bitlen );
+}
+
+static void * aes_ctx_alloc( void )
+{
+ mbedcrypto_aes_context *aes = mbedcrypto_calloc( 1, sizeof( mbedcrypto_aes_context ) );
+
+ if( aes == NULL )
+ return( NULL );
+
+ mbedcrypto_aes_init( aes );
+
+ return( aes );
+}
+
+static void aes_ctx_free( void *ctx )
+{
+ mbedcrypto_aes_free( (mbedcrypto_aes_context *) ctx );
+ mbedcrypto_free( ctx );
+}
+
+static const mbedcrypto_cipher_base_t aes_info = {
+ MBEDCRYPTO_CIPHER_ID_AES,
+ aes_crypt_ecb_wrap,
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+ aes_crypt_cbc_wrap,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CFB)
+ aes_crypt_cfb128_wrap,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CTR)
+ aes_crypt_ctr_wrap,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_STREAM)
+ NULL,
+#endif
+ aes_setkey_enc_wrap,
+ aes_setkey_dec_wrap,
+ aes_ctx_alloc,
+ aes_ctx_free
+};
+
+static const mbedcrypto_cipher_info_t aes_128_ecb_info = {
+ MBEDCRYPTO_CIPHER_AES_128_ECB,
+ MBEDCRYPTO_MODE_ECB,
+ 128,
+ "AES-128-ECB",
+ 16,
+ 0,
+ 16,
+ &aes_info
+};
+
+static const mbedcrypto_cipher_info_t aes_192_ecb_info = {
+ MBEDCRYPTO_CIPHER_AES_192_ECB,
+ MBEDCRYPTO_MODE_ECB,
+ 192,
+ "AES-192-ECB",
+ 16,
+ 0,
+ 16,
+ &aes_info
+};
+
+static const mbedcrypto_cipher_info_t aes_256_ecb_info = {
+ MBEDCRYPTO_CIPHER_AES_256_ECB,
+ MBEDCRYPTO_MODE_ECB,
+ 256,
+ "AES-256-ECB",
+ 16,
+ 0,
+ 16,
+ &aes_info
+};
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+static const mbedcrypto_cipher_info_t aes_128_cbc_info = {
+ MBEDCRYPTO_CIPHER_AES_128_CBC,
+ MBEDCRYPTO_MODE_CBC,
+ 128,
+ "AES-128-CBC",
+ 16,
+ 0,
+ 16,
+ &aes_info
+};
+
+static const mbedcrypto_cipher_info_t aes_192_cbc_info = {
+ MBEDCRYPTO_CIPHER_AES_192_CBC,
+ MBEDCRYPTO_MODE_CBC,
+ 192,
+ "AES-192-CBC",
+ 16,
+ 0,
+ 16,
+ &aes_info
+};
+
+static const mbedcrypto_cipher_info_t aes_256_cbc_info = {
+ MBEDCRYPTO_CIPHER_AES_256_CBC,
+ MBEDCRYPTO_MODE_CBC,
+ 256,
+ "AES-256-CBC",
+ 16,
+ 0,
+ 16,
+ &aes_info
+};
+#endif /* MBEDCRYPTO_CIPHER_MODE_CBC */
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CFB)
+static const mbedcrypto_cipher_info_t aes_128_cfb128_info = {
+ MBEDCRYPTO_CIPHER_AES_128_CFB128,
+ MBEDCRYPTO_MODE_CFB,
+ 128,
+ "AES-128-CFB128",
+ 16,
+ 0,
+ 16,
+ &aes_info
+};
+
+static const mbedcrypto_cipher_info_t aes_192_cfb128_info = {
+ MBEDCRYPTO_CIPHER_AES_192_CFB128,
+ MBEDCRYPTO_MODE_CFB,
+ 192,
+ "AES-192-CFB128",
+ 16,
+ 0,
+ 16,
+ &aes_info
+};
+
+static const mbedcrypto_cipher_info_t aes_256_cfb128_info = {
+ MBEDCRYPTO_CIPHER_AES_256_CFB128,
+ MBEDCRYPTO_MODE_CFB,
+ 256,
+ "AES-256-CFB128",
+ 16,
+ 0,
+ 16,
+ &aes_info
+};
+#endif /* MBEDCRYPTO_CIPHER_MODE_CFB */
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CTR)
+static const mbedcrypto_cipher_info_t aes_128_ctr_info = {
+ MBEDCRYPTO_CIPHER_AES_128_CTR,
+ MBEDCRYPTO_MODE_CTR,
+ 128,
+ "AES-128-CTR",
+ 16,
+ 0,
+ 16,
+ &aes_info
+};
+
+static const mbedcrypto_cipher_info_t aes_192_ctr_info = {
+ MBEDCRYPTO_CIPHER_AES_192_CTR,
+ MBEDCRYPTO_MODE_CTR,
+ 192,
+ "AES-192-CTR",
+ 16,
+ 0,
+ 16,
+ &aes_info
+};
+
+static const mbedcrypto_cipher_info_t aes_256_ctr_info = {
+ MBEDCRYPTO_CIPHER_AES_256_CTR,
+ MBEDCRYPTO_MODE_CTR,
+ 256,
+ "AES-256-CTR",
+ 16,
+ 0,
+ 16,
+ &aes_info
+};
+#endif /* MBEDCRYPTO_CIPHER_MODE_CTR */
+
+#if defined(MBEDCRYPTO_GCM_C)
+static int gcm_aes_setkey_wrap( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ return mbedcrypto_gcm_setkey( (mbedcrypto_gcm_context *) ctx, MBEDCRYPTO_CIPHER_ID_AES,
+ key, key_bitlen );
+}
+
+static const mbedcrypto_cipher_base_t gcm_aes_info = {
+ MBEDCRYPTO_CIPHER_ID_AES,
+ NULL,
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+ NULL,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CFB)
+ NULL,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CTR)
+ NULL,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_STREAM)
+ NULL,
+#endif
+ gcm_aes_setkey_wrap,
+ gcm_aes_setkey_wrap,
+ gcm_ctx_alloc,
+ gcm_ctx_free,
+};
+
+static const mbedcrypto_cipher_info_t aes_128_gcm_info = {
+ MBEDCRYPTO_CIPHER_AES_128_GCM,
+ MBEDCRYPTO_MODE_GCM,
+ 128,
+ "AES-128-GCM",
+ 12,
+ MBEDCRYPTO_CIPHER_VARIABLE_IV_LEN,
+ 16,
+ &gcm_aes_info
+};
+
+static const mbedcrypto_cipher_info_t aes_192_gcm_info = {
+ MBEDCRYPTO_CIPHER_AES_192_GCM,
+ MBEDCRYPTO_MODE_GCM,
+ 192,
+ "AES-192-GCM",
+ 12,
+ MBEDCRYPTO_CIPHER_VARIABLE_IV_LEN,
+ 16,
+ &gcm_aes_info
+};
+
+static const mbedcrypto_cipher_info_t aes_256_gcm_info = {
+ MBEDCRYPTO_CIPHER_AES_256_GCM,
+ MBEDCRYPTO_MODE_GCM,
+ 256,
+ "AES-256-GCM",
+ 12,
+ MBEDCRYPTO_CIPHER_VARIABLE_IV_LEN,
+ 16,
+ &gcm_aes_info
+};
+#endif /* MBEDCRYPTO_GCM_C */
+
+#if defined(MBEDCRYPTO_CCM_C)
+static int ccm_aes_setkey_wrap( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ return mbedcrypto_ccm_setkey( (mbedcrypto_ccm_context *) ctx, MBEDCRYPTO_CIPHER_ID_AES,
+ key, key_bitlen );
+}
+
+static const mbedcrypto_cipher_base_t ccm_aes_info = {
+ MBEDCRYPTO_CIPHER_ID_AES,
+ NULL,
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+ NULL,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CFB)
+ NULL,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CTR)
+ NULL,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_STREAM)
+ NULL,
+#endif
+ ccm_aes_setkey_wrap,
+ ccm_aes_setkey_wrap,
+ ccm_ctx_alloc,
+ ccm_ctx_free,
+};
+
+static const mbedcrypto_cipher_info_t aes_128_ccm_info = {
+ MBEDCRYPTO_CIPHER_AES_128_CCM,
+ MBEDCRYPTO_MODE_CCM,
+ 128,
+ "AES-128-CCM",
+ 12,
+ MBEDCRYPTO_CIPHER_VARIABLE_IV_LEN,
+ 16,
+ &ccm_aes_info
+};
+
+static const mbedcrypto_cipher_info_t aes_192_ccm_info = {
+ MBEDCRYPTO_CIPHER_AES_192_CCM,
+ MBEDCRYPTO_MODE_CCM,
+ 192,
+ "AES-192-CCM",
+ 12,
+ MBEDCRYPTO_CIPHER_VARIABLE_IV_LEN,
+ 16,
+ &ccm_aes_info
+};
+
+static const mbedcrypto_cipher_info_t aes_256_ccm_info = {
+ MBEDCRYPTO_CIPHER_AES_256_CCM,
+ MBEDCRYPTO_MODE_CCM,
+ 256,
+ "AES-256-CCM",
+ 12,
+ MBEDCRYPTO_CIPHER_VARIABLE_IV_LEN,
+ 16,
+ &ccm_aes_info
+};
+#endif /* MBEDCRYPTO_CCM_C */
+
+#endif /* MBEDCRYPTO_AES_C */
+
+#if defined(MBEDCRYPTO_CAMELLIA_C)
+
+static int camellia_crypt_ecb_wrap( void *ctx, mbedcrypto_operation_t operation,
+ const unsigned char *input, unsigned char *output )
+{
+ return mbedcrypto_camellia_crypt_ecb( (mbedcrypto_camellia_context *) ctx, operation, input,
+ output );
+}
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+static int camellia_crypt_cbc_wrap( void *ctx, mbedcrypto_operation_t operation,
+ size_t length, unsigned char *iv,
+ const unsigned char *input, unsigned char *output )
+{
+ return mbedcrypto_camellia_crypt_cbc( (mbedcrypto_camellia_context *) ctx, operation, length, iv,
+ input, output );
+}
+#endif /* MBEDCRYPTO_CIPHER_MODE_CBC */
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CFB)
+static int camellia_crypt_cfb128_wrap( void *ctx, mbedcrypto_operation_t operation,
+ size_t length, size_t *iv_off, unsigned char *iv,
+ const unsigned char *input, unsigned char *output )
+{
+ return mbedcrypto_camellia_crypt_cfb128( (mbedcrypto_camellia_context *) ctx, operation, length,
+ iv_off, iv, input, output );
+}
+#endif /* MBEDCRYPTO_CIPHER_MODE_CFB */
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CTR)
+static int camellia_crypt_ctr_wrap( void *ctx, size_t length, size_t *nc_off,
+ unsigned char *nonce_counter, unsigned char *stream_block,
+ const unsigned char *input, unsigned char *output )
+{
+ return mbedcrypto_camellia_crypt_ctr( (mbedcrypto_camellia_context *) ctx, length, nc_off,
+ nonce_counter, stream_block, input, output );
+}
+#endif /* MBEDCRYPTO_CIPHER_MODE_CTR */
+
+static int camellia_setkey_dec_wrap( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ return mbedcrypto_camellia_setkey_dec( (mbedcrypto_camellia_context *) ctx, key, key_bitlen );
+}
+
+static int camellia_setkey_enc_wrap( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ return mbedcrypto_camellia_setkey_enc( (mbedcrypto_camellia_context *) ctx, key, key_bitlen );
+}
+
+static void * camellia_ctx_alloc( void )
+{
+ mbedcrypto_camellia_context *ctx;
+ ctx = mbedcrypto_calloc( 1, sizeof( mbedcrypto_camellia_context ) );
+
+ if( ctx == NULL )
+ return( NULL );
+
+ mbedcrypto_camellia_init( ctx );
+
+ return( ctx );
+}
+
+static void camellia_ctx_free( void *ctx )
+{
+ mbedcrypto_camellia_free( (mbedcrypto_camellia_context *) ctx );
+ mbedcrypto_free( ctx );
+}
+
+static const mbedcrypto_cipher_base_t camellia_info = {
+ MBEDCRYPTO_CIPHER_ID_CAMELLIA,
+ camellia_crypt_ecb_wrap,
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+ camellia_crypt_cbc_wrap,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CFB)
+ camellia_crypt_cfb128_wrap,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CTR)
+ camellia_crypt_ctr_wrap,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_STREAM)
+ NULL,
+#endif
+ camellia_setkey_enc_wrap,
+ camellia_setkey_dec_wrap,
+ camellia_ctx_alloc,
+ camellia_ctx_free
+};
+
+static const mbedcrypto_cipher_info_t camellia_128_ecb_info = {
+ MBEDCRYPTO_CIPHER_CAMELLIA_128_ECB,
+ MBEDCRYPTO_MODE_ECB,
+ 128,
+ "CAMELLIA-128-ECB",
+ 16,
+ 0,
+ 16,
+ &camellia_info
+};
+
+static const mbedcrypto_cipher_info_t camellia_192_ecb_info = {
+ MBEDCRYPTO_CIPHER_CAMELLIA_192_ECB,
+ MBEDCRYPTO_MODE_ECB,
+ 192,
+ "CAMELLIA-192-ECB",
+ 16,
+ 0,
+ 16,
+ &camellia_info
+};
+
+static const mbedcrypto_cipher_info_t camellia_256_ecb_info = {
+ MBEDCRYPTO_CIPHER_CAMELLIA_256_ECB,
+ MBEDCRYPTO_MODE_ECB,
+ 256,
+ "CAMELLIA-256-ECB",
+ 16,
+ 0,
+ 16,
+ &camellia_info
+};
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+static const mbedcrypto_cipher_info_t camellia_128_cbc_info = {
+ MBEDCRYPTO_CIPHER_CAMELLIA_128_CBC,
+ MBEDCRYPTO_MODE_CBC,
+ 128,
+ "CAMELLIA-128-CBC",
+ 16,
+ 0,
+ 16,
+ &camellia_info
+};
+
+static const mbedcrypto_cipher_info_t camellia_192_cbc_info = {
+ MBEDCRYPTO_CIPHER_CAMELLIA_192_CBC,
+ MBEDCRYPTO_MODE_CBC,
+ 192,
+ "CAMELLIA-192-CBC",
+ 16,
+ 0,
+ 16,
+ &camellia_info
+};
+
+static const mbedcrypto_cipher_info_t camellia_256_cbc_info = {
+ MBEDCRYPTO_CIPHER_CAMELLIA_256_CBC,
+ MBEDCRYPTO_MODE_CBC,
+ 256,
+ "CAMELLIA-256-CBC",
+ 16,
+ 0,
+ 16,
+ &camellia_info
+};
+#endif /* MBEDCRYPTO_CIPHER_MODE_CBC */
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CFB)
+static const mbedcrypto_cipher_info_t camellia_128_cfb128_info = {
+ MBEDCRYPTO_CIPHER_CAMELLIA_128_CFB128,
+ MBEDCRYPTO_MODE_CFB,
+ 128,
+ "CAMELLIA-128-CFB128",
+ 16,
+ 0,
+ 16,
+ &camellia_info
+};
+
+static const mbedcrypto_cipher_info_t camellia_192_cfb128_info = {
+ MBEDCRYPTO_CIPHER_CAMELLIA_192_CFB128,
+ MBEDCRYPTO_MODE_CFB,
+ 192,
+ "CAMELLIA-192-CFB128",
+ 16,
+ 0,
+ 16,
+ &camellia_info
+};
+
+static const mbedcrypto_cipher_info_t camellia_256_cfb128_info = {
+ MBEDCRYPTO_CIPHER_CAMELLIA_256_CFB128,
+ MBEDCRYPTO_MODE_CFB,
+ 256,
+ "CAMELLIA-256-CFB128",
+ 16,
+ 0,
+ 16,
+ &camellia_info
+};
+#endif /* MBEDCRYPTO_CIPHER_MODE_CFB */
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CTR)
+static const mbedcrypto_cipher_info_t camellia_128_ctr_info = {
+ MBEDCRYPTO_CIPHER_CAMELLIA_128_CTR,
+ MBEDCRYPTO_MODE_CTR,
+ 128,
+ "CAMELLIA-128-CTR",
+ 16,
+ 0,
+ 16,
+ &camellia_info
+};
+
+static const mbedcrypto_cipher_info_t camellia_192_ctr_info = {
+ MBEDCRYPTO_CIPHER_CAMELLIA_192_CTR,
+ MBEDCRYPTO_MODE_CTR,
+ 192,
+ "CAMELLIA-192-CTR",
+ 16,
+ 0,
+ 16,
+ &camellia_info
+};
+
+static const mbedcrypto_cipher_info_t camellia_256_ctr_info = {
+ MBEDCRYPTO_CIPHER_CAMELLIA_256_CTR,
+ MBEDCRYPTO_MODE_CTR,
+ 256,
+ "CAMELLIA-256-CTR",
+ 16,
+ 0,
+ 16,
+ &camellia_info
+};
+#endif /* MBEDCRYPTO_CIPHER_MODE_CTR */
+
+#if defined(MBEDCRYPTO_GCM_C)
+static int gcm_camellia_setkey_wrap( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ return mbedcrypto_gcm_setkey( (mbedcrypto_gcm_context *) ctx, MBEDCRYPTO_CIPHER_ID_CAMELLIA,
+ key, key_bitlen );
+}
+
+static const mbedcrypto_cipher_base_t gcm_camellia_info = {
+ MBEDCRYPTO_CIPHER_ID_CAMELLIA,
+ NULL,
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+ NULL,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CFB)
+ NULL,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CTR)
+ NULL,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_STREAM)
+ NULL,
+#endif
+ gcm_camellia_setkey_wrap,
+ gcm_camellia_setkey_wrap,
+ gcm_ctx_alloc,
+ gcm_ctx_free,
+};
+
+static const mbedcrypto_cipher_info_t camellia_128_gcm_info = {
+ MBEDCRYPTO_CIPHER_CAMELLIA_128_GCM,
+ MBEDCRYPTO_MODE_GCM,
+ 128,
+ "CAMELLIA-128-GCM",
+ 12,
+ MBEDCRYPTO_CIPHER_VARIABLE_IV_LEN,
+ 16,
+ &gcm_camellia_info
+};
+
+static const mbedcrypto_cipher_info_t camellia_192_gcm_info = {
+ MBEDCRYPTO_CIPHER_CAMELLIA_192_GCM,
+ MBEDCRYPTO_MODE_GCM,
+ 192,
+ "CAMELLIA-192-GCM",
+ 12,
+ MBEDCRYPTO_CIPHER_VARIABLE_IV_LEN,
+ 16,
+ &gcm_camellia_info
+};
+
+static const mbedcrypto_cipher_info_t camellia_256_gcm_info = {
+ MBEDCRYPTO_CIPHER_CAMELLIA_256_GCM,
+ MBEDCRYPTO_MODE_GCM,
+ 256,
+ "CAMELLIA-256-GCM",
+ 12,
+ MBEDCRYPTO_CIPHER_VARIABLE_IV_LEN,
+ 16,
+ &gcm_camellia_info
+};
+#endif /* MBEDCRYPTO_GCM_C */
+
+#if defined(MBEDCRYPTO_CCM_C)
+static int ccm_camellia_setkey_wrap( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ return mbedcrypto_ccm_setkey( (mbedcrypto_ccm_context *) ctx, MBEDCRYPTO_CIPHER_ID_CAMELLIA,
+ key, key_bitlen );
+}
+
+static const mbedcrypto_cipher_base_t ccm_camellia_info = {
+ MBEDCRYPTO_CIPHER_ID_CAMELLIA,
+ NULL,
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+ NULL,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CFB)
+ NULL,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CTR)
+ NULL,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_STREAM)
+ NULL,
+#endif
+ ccm_camellia_setkey_wrap,
+ ccm_camellia_setkey_wrap,
+ ccm_ctx_alloc,
+ ccm_ctx_free,
+};
+
+static const mbedcrypto_cipher_info_t camellia_128_ccm_info = {
+ MBEDCRYPTO_CIPHER_CAMELLIA_128_CCM,
+ MBEDCRYPTO_MODE_CCM,
+ 128,
+ "CAMELLIA-128-CCM",
+ 12,
+ MBEDCRYPTO_CIPHER_VARIABLE_IV_LEN,
+ 16,
+ &ccm_camellia_info
+};
+
+static const mbedcrypto_cipher_info_t camellia_192_ccm_info = {
+ MBEDCRYPTO_CIPHER_CAMELLIA_192_CCM,
+ MBEDCRYPTO_MODE_CCM,
+ 192,
+ "CAMELLIA-192-CCM",
+ 12,
+ MBEDCRYPTO_CIPHER_VARIABLE_IV_LEN,
+ 16,
+ &ccm_camellia_info
+};
+
+static const mbedcrypto_cipher_info_t camellia_256_ccm_info = {
+ MBEDCRYPTO_CIPHER_CAMELLIA_256_CCM,
+ MBEDCRYPTO_MODE_CCM,
+ 256,
+ "CAMELLIA-256-CCM",
+ 12,
+ MBEDCRYPTO_CIPHER_VARIABLE_IV_LEN,
+ 16,
+ &ccm_camellia_info
+};
+#endif /* MBEDCRYPTO_CCM_C */
+
+#endif /* MBEDCRYPTO_CAMELLIA_C */
+
+#if defined(MBEDCRYPTO_DES_C)
+
+static int des_crypt_ecb_wrap( void *ctx, mbedcrypto_operation_t operation,
+ const unsigned char *input, unsigned char *output )
+{
+ ((void) operation);
+ return mbedcrypto_des_crypt_ecb( (mbedcrypto_des_context *) ctx, input, output );
+}
+
+static int des3_crypt_ecb_wrap( void *ctx, mbedcrypto_operation_t operation,
+ const unsigned char *input, unsigned char *output )
+{
+ ((void) operation);
+ return mbedcrypto_des3_crypt_ecb( (mbedcrypto_des3_context *) ctx, input, output );
+}
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+static int des_crypt_cbc_wrap( void *ctx, mbedcrypto_operation_t operation, size_t length,
+ unsigned char *iv, const unsigned char *input, unsigned char *output )
+{
+ return mbedcrypto_des_crypt_cbc( (mbedcrypto_des_context *) ctx, operation, length, iv, input,
+ output );
+}
+#endif /* MBEDCRYPTO_CIPHER_MODE_CBC */
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+static int des3_crypt_cbc_wrap( void *ctx, mbedcrypto_operation_t operation, size_t length,
+ unsigned char *iv, const unsigned char *input, unsigned char *output )
+{
+ return mbedcrypto_des3_crypt_cbc( (mbedcrypto_des3_context *) ctx, operation, length, iv, input,
+ output );
+}
+#endif /* MBEDCRYPTO_CIPHER_MODE_CBC */
+
+static int des_setkey_dec_wrap( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ ((void) key_bitlen);
+
+ return mbedcrypto_des_setkey_dec( (mbedcrypto_des_context *) ctx, key );
+}
+
+static int des_setkey_enc_wrap( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ ((void) key_bitlen);
+
+ return mbedcrypto_des_setkey_enc( (mbedcrypto_des_context *) ctx, key );
+}
+
+static int des3_set2key_dec_wrap( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ ((void) key_bitlen);
+
+ return mbedcrypto_des3_set2key_dec( (mbedcrypto_des3_context *) ctx, key );
+}
+
+static int des3_set2key_enc_wrap( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ ((void) key_bitlen);
+
+ return mbedcrypto_des3_set2key_enc( (mbedcrypto_des3_context *) ctx, key );
+}
+
+static int des3_set3key_dec_wrap( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ ((void) key_bitlen);
+
+ return mbedcrypto_des3_set3key_dec( (mbedcrypto_des3_context *) ctx, key );
+}
+
+static int des3_set3key_enc_wrap( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ ((void) key_bitlen);
+
+ return mbedcrypto_des3_set3key_enc( (mbedcrypto_des3_context *) ctx, key );
+}
+
+static void * des_ctx_alloc( void )
+{
+ mbedcrypto_des_context *des = mbedcrypto_calloc( 1, sizeof( mbedcrypto_des_context ) );
+
+ if( des == NULL )
+ return( NULL );
+
+ mbedcrypto_des_init( des );
+
+ return( des );
+}
+
+static void des_ctx_free( void *ctx )
+{
+ mbedcrypto_des_free( (mbedcrypto_des_context *) ctx );
+ mbedcrypto_free( ctx );
+}
+
+static void * des3_ctx_alloc( void )
+{
+ mbedcrypto_des3_context *des3;
+ des3 = mbedcrypto_calloc( 1, sizeof( mbedcrypto_des3_context ) );
+
+ if( des3 == NULL )
+ return( NULL );
+
+ mbedcrypto_des3_init( des3 );
+
+ return( des3 );
+}
+
+static void des3_ctx_free( void *ctx )
+{
+ mbedcrypto_des3_free( (mbedcrypto_des3_context *) ctx );
+ mbedcrypto_free( ctx );
+}
+
+static const mbedcrypto_cipher_base_t des_info = {
+ MBEDCRYPTO_CIPHER_ID_DES,
+ des_crypt_ecb_wrap,
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+ des_crypt_cbc_wrap,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CFB)
+ NULL,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CTR)
+ NULL,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_STREAM)
+ NULL,
+#endif
+ des_setkey_enc_wrap,
+ des_setkey_dec_wrap,
+ des_ctx_alloc,
+ des_ctx_free
+};
+
+static const mbedcrypto_cipher_info_t des_ecb_info = {
+ MBEDCRYPTO_CIPHER_DES_ECB,
+ MBEDCRYPTO_MODE_ECB,
+ MBEDCRYPTO_KEY_LENGTH_DES,
+ "DES-ECB",
+ 8,
+ 0,
+ 8,
+ &des_info
+};
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+static const mbedcrypto_cipher_info_t des_cbc_info = {
+ MBEDCRYPTO_CIPHER_DES_CBC,
+ MBEDCRYPTO_MODE_CBC,
+ MBEDCRYPTO_KEY_LENGTH_DES,
+ "DES-CBC",
+ 8,
+ 0,
+ 8,
+ &des_info
+};
+#endif /* MBEDCRYPTO_CIPHER_MODE_CBC */
+
+static const mbedcrypto_cipher_base_t des_ede_info = {
+ MBEDCRYPTO_CIPHER_ID_DES,
+ des3_crypt_ecb_wrap,
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+ des3_crypt_cbc_wrap,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CFB)
+ NULL,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CTR)
+ NULL,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_STREAM)
+ NULL,
+#endif
+ des3_set2key_enc_wrap,
+ des3_set2key_dec_wrap,
+ des3_ctx_alloc,
+ des3_ctx_free
+};
+
+static const mbedcrypto_cipher_info_t des_ede_ecb_info = {
+ MBEDCRYPTO_CIPHER_DES_EDE_ECB,
+ MBEDCRYPTO_MODE_ECB,
+ MBEDCRYPTO_KEY_LENGTH_DES_EDE,
+ "DES-EDE-ECB",
+ 8,
+ 0,
+ 8,
+ &des_ede_info
+};
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+static const mbedcrypto_cipher_info_t des_ede_cbc_info = {
+ MBEDCRYPTO_CIPHER_DES_EDE_CBC,
+ MBEDCRYPTO_MODE_CBC,
+ MBEDCRYPTO_KEY_LENGTH_DES_EDE,
+ "DES-EDE-CBC",
+ 8,
+ 0,
+ 8,
+ &des_ede_info
+};
+#endif /* MBEDCRYPTO_CIPHER_MODE_CBC */
+
+static const mbedcrypto_cipher_base_t des_ede3_info = {
+ MBEDCRYPTO_CIPHER_ID_3DES,
+ des3_crypt_ecb_wrap,
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+ des3_crypt_cbc_wrap,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CFB)
+ NULL,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CTR)
+ NULL,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_STREAM)
+ NULL,
+#endif
+ des3_set3key_enc_wrap,
+ des3_set3key_dec_wrap,
+ des3_ctx_alloc,
+ des3_ctx_free
+};
+
+static const mbedcrypto_cipher_info_t des_ede3_ecb_info = {
+ MBEDCRYPTO_CIPHER_DES_EDE3_ECB,
+ MBEDCRYPTO_MODE_ECB,
+ MBEDCRYPTO_KEY_LENGTH_DES_EDE3,
+ "DES-EDE3-ECB",
+ 8,
+ 0,
+ 8,
+ &des_ede3_info
+};
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+static const mbedcrypto_cipher_info_t des_ede3_cbc_info = {
+ MBEDCRYPTO_CIPHER_DES_EDE3_CBC,
+ MBEDCRYPTO_MODE_CBC,
+ MBEDCRYPTO_KEY_LENGTH_DES_EDE3,
+ "DES-EDE3-CBC",
+ 8,
+ 0,
+ 8,
+ &des_ede3_info
+};
+#endif /* MBEDCRYPTO_CIPHER_MODE_CBC */
+#endif /* MBEDCRYPTO_DES_C */
+
+#if defined(MBEDCRYPTO_BLOWFISH_C)
+
+static int blowfish_crypt_ecb_wrap( void *ctx, mbedcrypto_operation_t operation,
+ const unsigned char *input, unsigned char *output )
+{
+ return mbedcrypto_blowfish_crypt_ecb( (mbedcrypto_blowfish_context *) ctx, operation, input,
+ output );
+}
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+static int blowfish_crypt_cbc_wrap( void *ctx, mbedcrypto_operation_t operation,
+ size_t length, unsigned char *iv, const unsigned char *input,
+ unsigned char *output )
+{
+ return mbedcrypto_blowfish_crypt_cbc( (mbedcrypto_blowfish_context *) ctx, operation, length, iv,
+ input, output );
+}
+#endif /* MBEDCRYPTO_CIPHER_MODE_CBC */
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CFB)
+static int blowfish_crypt_cfb64_wrap( void *ctx, mbedcrypto_operation_t operation,
+ size_t length, size_t *iv_off, unsigned char *iv,
+ const unsigned char *input, unsigned char *output )
+{
+ return mbedcrypto_blowfish_crypt_cfb64( (mbedcrypto_blowfish_context *) ctx, operation, length,
+ iv_off, iv, input, output );
+}
+#endif /* MBEDCRYPTO_CIPHER_MODE_CFB */
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CTR)
+static int blowfish_crypt_ctr_wrap( void *ctx, size_t length, size_t *nc_off,
+ unsigned char *nonce_counter, unsigned char *stream_block,
+ const unsigned char *input, unsigned char *output )
+{
+ return mbedcrypto_blowfish_crypt_ctr( (mbedcrypto_blowfish_context *) ctx, length, nc_off,
+ nonce_counter, stream_block, input, output );
+}
+#endif /* MBEDCRYPTO_CIPHER_MODE_CTR */
+
+static int blowfish_setkey_wrap( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ return mbedcrypto_blowfish_setkey( (mbedcrypto_blowfish_context *) ctx, key, key_bitlen );
+}
+
+static void * blowfish_ctx_alloc( void )
+{
+ mbedcrypto_blowfish_context *ctx;
+ ctx = mbedcrypto_calloc( 1, sizeof( mbedcrypto_blowfish_context ) );
+
+ if( ctx == NULL )
+ return( NULL );
+
+ mbedcrypto_blowfish_init( ctx );
+
+ return( ctx );
+}
+
+static void blowfish_ctx_free( void *ctx )
+{
+ mbedcrypto_blowfish_free( (mbedcrypto_blowfish_context *) ctx );
+ mbedcrypto_free( ctx );
+}
+
+static const mbedcrypto_cipher_base_t blowfish_info = {
+ MBEDCRYPTO_CIPHER_ID_BLOWFISH,
+ blowfish_crypt_ecb_wrap,
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+ blowfish_crypt_cbc_wrap,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CFB)
+ blowfish_crypt_cfb64_wrap,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CTR)
+ blowfish_crypt_ctr_wrap,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_STREAM)
+ NULL,
+#endif
+ blowfish_setkey_wrap,
+ blowfish_setkey_wrap,
+ blowfish_ctx_alloc,
+ blowfish_ctx_free
+};
+
+static const mbedcrypto_cipher_info_t blowfish_ecb_info = {
+ MBEDCRYPTO_CIPHER_BLOWFISH_ECB,
+ MBEDCRYPTO_MODE_ECB,
+ 128,
+ "BLOWFISH-ECB",
+ 8,
+ MBEDCRYPTO_CIPHER_VARIABLE_KEY_LEN,
+ 8,
+ &blowfish_info
+};
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+static const mbedcrypto_cipher_info_t blowfish_cbc_info = {
+ MBEDCRYPTO_CIPHER_BLOWFISH_CBC,
+ MBEDCRYPTO_MODE_CBC,
+ 128,
+ "BLOWFISH-CBC",
+ 8,
+ MBEDCRYPTO_CIPHER_VARIABLE_KEY_LEN,
+ 8,
+ &blowfish_info
+};
+#endif /* MBEDCRYPTO_CIPHER_MODE_CBC */
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CFB)
+static const mbedcrypto_cipher_info_t blowfish_cfb64_info = {
+ MBEDCRYPTO_CIPHER_BLOWFISH_CFB64,
+ MBEDCRYPTO_MODE_CFB,
+ 128,
+ "BLOWFISH-CFB64",
+ 8,
+ MBEDCRYPTO_CIPHER_VARIABLE_KEY_LEN,
+ 8,
+ &blowfish_info
+};
+#endif /* MBEDCRYPTO_CIPHER_MODE_CFB */
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CTR)
+static const mbedcrypto_cipher_info_t blowfish_ctr_info = {
+ MBEDCRYPTO_CIPHER_BLOWFISH_CTR,
+ MBEDCRYPTO_MODE_CTR,
+ 128,
+ "BLOWFISH-CTR",
+ 8,
+ MBEDCRYPTO_CIPHER_VARIABLE_KEY_LEN,
+ 8,
+ &blowfish_info
+};
+#endif /* MBEDCRYPTO_CIPHER_MODE_CTR */
+#endif /* MBEDCRYPTO_BLOWFISH_C */
+
+#if defined(MBEDCRYPTO_ARC4_C)
+static int arc4_crypt_stream_wrap( void *ctx, size_t length,
+ const unsigned char *input,
+ unsigned char *output )
+{
+ return( mbedcrypto_arc4_crypt( (mbedcrypto_arc4_context *) ctx, length, input, output ) );
+}
+
+static int arc4_setkey_wrap( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ /* we get key_bitlen in bits, arc4 expects it in bytes */
+ if( key_bitlen % 8 != 0 )
+ return( MBEDCRYPTO_ERR_CIPHER_BAD_INPUT_DATA );
+
+ mbedcrypto_arc4_setup( (mbedcrypto_arc4_context *) ctx, key, key_bitlen / 8 );
+ return( 0 );
+}
+
+static void * arc4_ctx_alloc( void )
+{
+ mbedcrypto_arc4_context *ctx;
+ ctx = mbedcrypto_calloc( 1, sizeof( mbedcrypto_arc4_context ) );
+
+ if( ctx == NULL )
+ return( NULL );
+
+ mbedcrypto_arc4_init( ctx );
+
+ return( ctx );
+}
+
+static void arc4_ctx_free( void *ctx )
+{
+ mbedcrypto_arc4_free( (mbedcrypto_arc4_context *) ctx );
+ mbedcrypto_free( ctx );
+}
+
+static const mbedcrypto_cipher_base_t arc4_base_info = {
+ MBEDCRYPTO_CIPHER_ID_ARC4,
+ NULL,
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+ NULL,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CFB)
+ NULL,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CTR)
+ NULL,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_STREAM)
+ arc4_crypt_stream_wrap,
+#endif
+ arc4_setkey_wrap,
+ arc4_setkey_wrap,
+ arc4_ctx_alloc,
+ arc4_ctx_free
+};
+
+static const mbedcrypto_cipher_info_t arc4_128_info = {
+ MBEDCRYPTO_CIPHER_ARC4_128,
+ MBEDCRYPTO_MODE_STREAM,
+ 128,
+ "ARC4-128",
+ 0,
+ 0,
+ 1,
+ &arc4_base_info
+};
+#endif /* MBEDCRYPTO_ARC4_C */
+
+#if defined(MBEDCRYPTO_CIPHER_NULL_CIPHER)
+static int null_crypt_stream( void *ctx, size_t length,
+ const unsigned char *input,
+ unsigned char *output )
+{
+ ((void) ctx);
+ memmove( output, input, length );
+ return( 0 );
+}
+
+static int null_setkey( void *ctx, const unsigned char *key,
+ unsigned int key_bitlen )
+{
+ ((void) ctx);
+ ((void) key);
+ ((void) key_bitlen);
+
+ return( 0 );
+}
+
+static void * null_ctx_alloc( void )
+{
+ return( (void *) 1 );
+}
+
+static void null_ctx_free( void *ctx )
+{
+ ((void) ctx);
+}
+
+static const mbedcrypto_cipher_base_t null_base_info = {
+ MBEDCRYPTO_CIPHER_ID_NULL,
+ NULL,
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+ NULL,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CFB)
+ NULL,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CTR)
+ NULL,
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_STREAM)
+ null_crypt_stream,
+#endif
+ null_setkey,
+ null_setkey,
+ null_ctx_alloc,
+ null_ctx_free
+};
+
+static const mbedcrypto_cipher_info_t null_cipher_info = {
+ MBEDCRYPTO_CIPHER_NULL,
+ MBEDCRYPTO_MODE_STREAM,
+ 0,
+ "NULL",
+ 0,
+ 0,
+ 1,
+ &null_base_info
+};
+#endif /* defined(MBEDCRYPTO_CIPHER_NULL_CIPHER) */
+
+const mbedcrypto_cipher_definition_t mbedcrypto_cipher_definitions[] =
+{
+#if defined(MBEDCRYPTO_AES_C)
+ { MBEDCRYPTO_CIPHER_AES_128_ECB, &aes_128_ecb_info },
+ { MBEDCRYPTO_CIPHER_AES_192_ECB, &aes_192_ecb_info },
+ { MBEDCRYPTO_CIPHER_AES_256_ECB, &aes_256_ecb_info },
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+ { MBEDCRYPTO_CIPHER_AES_128_CBC, &aes_128_cbc_info },
+ { MBEDCRYPTO_CIPHER_AES_192_CBC, &aes_192_cbc_info },
+ { MBEDCRYPTO_CIPHER_AES_256_CBC, &aes_256_cbc_info },
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CFB)
+ { MBEDCRYPTO_CIPHER_AES_128_CFB128, &aes_128_cfb128_info },
+ { MBEDCRYPTO_CIPHER_AES_192_CFB128, &aes_192_cfb128_info },
+ { MBEDCRYPTO_CIPHER_AES_256_CFB128, &aes_256_cfb128_info },
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CTR)
+ { MBEDCRYPTO_CIPHER_AES_128_CTR, &aes_128_ctr_info },
+ { MBEDCRYPTO_CIPHER_AES_192_CTR, &aes_192_ctr_info },
+ { MBEDCRYPTO_CIPHER_AES_256_CTR, &aes_256_ctr_info },
+#endif
+#if defined(MBEDCRYPTO_GCM_C)
+ { MBEDCRYPTO_CIPHER_AES_128_GCM, &aes_128_gcm_info },
+ { MBEDCRYPTO_CIPHER_AES_192_GCM, &aes_192_gcm_info },
+ { MBEDCRYPTO_CIPHER_AES_256_GCM, &aes_256_gcm_info },
+#endif
+#if defined(MBEDCRYPTO_CCM_C)
+ { MBEDCRYPTO_CIPHER_AES_128_CCM, &aes_128_ccm_info },
+ { MBEDCRYPTO_CIPHER_AES_192_CCM, &aes_192_ccm_info },
+ { MBEDCRYPTO_CIPHER_AES_256_CCM, &aes_256_ccm_info },
+#endif
+#endif /* MBEDCRYPTO_AES_C */
+
+#if defined(MBEDCRYPTO_ARC4_C)
+ { MBEDCRYPTO_CIPHER_ARC4_128, &arc4_128_info },
+#endif
+
+#if defined(MBEDCRYPTO_BLOWFISH_C)
+ { MBEDCRYPTO_CIPHER_BLOWFISH_ECB, &blowfish_ecb_info },
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+ { MBEDCRYPTO_CIPHER_BLOWFISH_CBC, &blowfish_cbc_info },
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CFB)
+ { MBEDCRYPTO_CIPHER_BLOWFISH_CFB64, &blowfish_cfb64_info },
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CTR)
+ { MBEDCRYPTO_CIPHER_BLOWFISH_CTR, &blowfish_ctr_info },
+#endif
+#endif /* MBEDCRYPTO_BLOWFISH_C */
+
+#if defined(MBEDCRYPTO_CAMELLIA_C)
+ { MBEDCRYPTO_CIPHER_CAMELLIA_128_ECB, &camellia_128_ecb_info },
+ { MBEDCRYPTO_CIPHER_CAMELLIA_192_ECB, &camellia_192_ecb_info },
+ { MBEDCRYPTO_CIPHER_CAMELLIA_256_ECB, &camellia_256_ecb_info },
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+ { MBEDCRYPTO_CIPHER_CAMELLIA_128_CBC, &camellia_128_cbc_info },
+ { MBEDCRYPTO_CIPHER_CAMELLIA_192_CBC, &camellia_192_cbc_info },
+ { MBEDCRYPTO_CIPHER_CAMELLIA_256_CBC, &camellia_256_cbc_info },
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CFB)
+ { MBEDCRYPTO_CIPHER_CAMELLIA_128_CFB128, &camellia_128_cfb128_info },
+ { MBEDCRYPTO_CIPHER_CAMELLIA_192_CFB128, &camellia_192_cfb128_info },
+ { MBEDCRYPTO_CIPHER_CAMELLIA_256_CFB128, &camellia_256_cfb128_info },
+#endif
+#if defined(MBEDCRYPTO_CIPHER_MODE_CTR)
+ { MBEDCRYPTO_CIPHER_CAMELLIA_128_CTR, &camellia_128_ctr_info },
+ { MBEDCRYPTO_CIPHER_CAMELLIA_192_CTR, &camellia_192_ctr_info },
+ { MBEDCRYPTO_CIPHER_CAMELLIA_256_CTR, &camellia_256_ctr_info },
+#endif
+#if defined(MBEDCRYPTO_GCM_C)
+ { MBEDCRYPTO_CIPHER_CAMELLIA_128_GCM, &camellia_128_gcm_info },
+ { MBEDCRYPTO_CIPHER_CAMELLIA_192_GCM, &camellia_192_gcm_info },
+ { MBEDCRYPTO_CIPHER_CAMELLIA_256_GCM, &camellia_256_gcm_info },
+#endif
+#if defined(MBEDCRYPTO_CCM_C)
+ { MBEDCRYPTO_CIPHER_CAMELLIA_128_CCM, &camellia_128_ccm_info },
+ { MBEDCRYPTO_CIPHER_CAMELLIA_192_CCM, &camellia_192_ccm_info },
+ { MBEDCRYPTO_CIPHER_CAMELLIA_256_CCM, &camellia_256_ccm_info },
+#endif
+#endif /* MBEDCRYPTO_CAMELLIA_C */
+
+#if defined(MBEDCRYPTO_DES_C)
+ { MBEDCRYPTO_CIPHER_DES_ECB, &des_ecb_info },
+ { MBEDCRYPTO_CIPHER_DES_EDE_ECB, &des_ede_ecb_info },
+ { MBEDCRYPTO_CIPHER_DES_EDE3_ECB, &des_ede3_ecb_info },
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+ { MBEDCRYPTO_CIPHER_DES_CBC, &des_cbc_info },
+ { MBEDCRYPTO_CIPHER_DES_EDE_CBC, &des_ede_cbc_info },
+ { MBEDCRYPTO_CIPHER_DES_EDE3_CBC, &des_ede3_cbc_info },
+#endif
+#endif /* MBEDCRYPTO_DES_C */
+
+#if defined(MBEDCRYPTO_CIPHER_NULL_CIPHER)
+ { MBEDCRYPTO_CIPHER_NULL, &null_cipher_info },
+#endif /* MBEDCRYPTO_CIPHER_NULL_CIPHER */
+
+ { MBEDCRYPTO_CIPHER_NONE, NULL }
+};
+
+#define NUM_CIPHERS sizeof mbedcrypto_cipher_definitions / sizeof mbedcrypto_cipher_definitions[0]
+int mbedcrypto_cipher_supported[NUM_CIPHERS];
+
+#endif /* MBEDCRYPTO_CIPHER_C */
diff --git a/library/cmac.c b/library/cmac.c
new file mode 100644
index 0000000..e12f7bd
--- /dev/null
+++ b/library/cmac.c
@@ -0,0 +1,1076 @@
+/**
+ * \file cmac.c
+ *
+ * \brief NIST SP800-38B compliant CMAC implementation for AES and 3DES
+ *
+ * Copyright (C) 2006-2016, 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 Crypto (https://tls.mbed.org)
+ */
+
+/*
+ * References:
+ *
+ * - NIST SP 800-38B Recommendation for Block Cipher Modes of Operation: The
+ * CMAC Mode for Authentication
+ * http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38b.pdf
+ *
+ * - RFC 4493 - The AES-CMAC Algorithm
+ * https://tools.ietf.org/html/rfc4493
+ *
+ * - RFC 4615 - The Advanced Encryption Standard-Cipher-based Message
+ * Authentication Code-Pseudo-Random Function-128 (AES-CMAC-PRF-128)
+ * Algorithm for the Internet Key Exchange Protocol (IKE)
+ * https://tools.ietf.org/html/rfc4615
+ *
+ * Additional test vectors: ISO/IEC 9797-1
+ *
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_CMAC_C)
+
+#include "mbedcrypto/cmac.h"
+#include "mbedcrypto/platform_util.h"
+
+#include <string.h>
+
+
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#include <stdlib.h>
+#define mbedcrypto_calloc calloc
+#define mbedcrypto_free free
+#if defined(MBEDCRYPTO_SELF_TEST)
+#include <stdio.h>
+#define mbedcrypto_printf printf
+#endif /* MBEDCRYPTO_SELF_TEST */
+#endif /* MBEDCRYPTO_PLATFORM_C */
+
+#if !defined(MBEDCRYPTO_CMAC_ALT) || defined(MBEDCRYPTO_SELF_TEST)
+
+/*
+ * Multiplication by u in the Galois field of GF(2^n)
+ *
+ * As explained in NIST SP 800-38B, this can be computed:
+ *
+ * If MSB(p) = 0, then p = (p << 1)
+ * If MSB(p) = 1, then p = (p << 1) ^ R_n
+ * with R_64 = 0x1B and R_128 = 0x87
+ *
+ * Input and output MUST NOT point to the same buffer
+ * Block size must be 8 bytes or 16 bytes - the block sizes for DES and AES.
+ */
+static int cmac_multiply_by_u( unsigned char *output,
+ const unsigned char *input,
+ size_t blocksize )
+{
+ const unsigned char R_128 = 0x87;
+ const unsigned char R_64 = 0x1B;
+ unsigned char R_n, mask;
+ unsigned char overflow = 0x00;
+ int i;
+
+ if( blocksize == MBEDCRYPTO_AES_BLOCK_SIZE )
+ {
+ R_n = R_128;
+ }
+ else if( blocksize == MBEDCRYPTO_DES3_BLOCK_SIZE )
+ {
+ R_n = R_64;
+ }
+ else
+ {
+ return( MBEDCRYPTO_ERR_CIPHER_BAD_INPUT_DATA );
+ }
+
+ for( i = (int)blocksize - 1; i >= 0; i-- )
+ {
+ output[i] = input[i] << 1 | overflow;
+ overflow = input[i] >> 7;
+ }
+
+ /* mask = ( input[0] >> 7 ) ? 0xff : 0x00
+ * using bit operations to avoid branches */
+
+ /* MSVC has a warning about unary minus on unsigned, but this is
+ * well-defined and precisely what we want to do here */
+#if defined(_MSC_VER)
+#pragma warning( push )
+#pragma warning( disable : 4146 )
+#endif
+ mask = - ( input[0] >> 7 );
+#if defined(_MSC_VER)
+#pragma warning( pop )
+#endif
+
+ output[ blocksize - 1 ] ^= R_n & mask;
+
+ return( 0 );
+}
+
+/*
+ * Generate subkeys
+ *
+ * - as specified by RFC 4493, section 2.3 Subkey Generation Algorithm
+ */
+static int cmac_generate_subkeys( mbedcrypto_cipher_context_t *ctx,
+ unsigned char* K1, unsigned char* K2 )
+{
+ int ret;
+ unsigned char L[MBEDCRYPTO_CIPHER_BLKSIZE_MAX];
+ size_t olen, block_size;
+
+ mbedcrypto_platform_zeroize( L, sizeof( L ) );
+
+ block_size = ctx->cipher_info->block_size;
+
+ /* Calculate Ek(0) */
+ if( ( ret = mbedcrypto_cipher_update( ctx, L, block_size, L, &olen ) ) != 0 )
+ goto exit;
+
+ /*
+ * Generate K1 and K2
+ */
+ if( ( ret = cmac_multiply_by_u( K1, L , block_size ) ) != 0 )
+ goto exit;
+
+ if( ( ret = cmac_multiply_by_u( K2, K1 , block_size ) ) != 0 )
+ goto exit;
+
+exit:
+ mbedcrypto_platform_zeroize( L, sizeof( L ) );
+
+ return( ret );
+}
+#endif /* !defined(MBEDCRYPTO_CMAC_ALT) || defined(MBEDCRYPTO_SELF_TEST) */
+
+#if !defined(MBEDCRYPTO_CMAC_ALT)
+static void cmac_xor_block( unsigned char *output, const unsigned char *input1,
+ const unsigned char *input2,
+ const size_t block_size )
+{
+ size_t idx;
+
+ for( idx = 0; idx < block_size; idx++ )
+ output[ idx ] = input1[ idx ] ^ input2[ idx ];
+}
+
+/*
+ * Create padded last block from (partial) last block.
+ *
+ * We can't use the padding option from the cipher layer, as it only works for
+ * CBC and we use ECB mode, and anyway we need to XOR K1 or K2 in addition.
+ */
+static void cmac_pad( unsigned char padded_block[MBEDCRYPTO_CIPHER_BLKSIZE_MAX],
+ size_t padded_block_len,
+ const unsigned char *last_block,
+ size_t last_block_len )
+{
+ size_t j;
+
+ for( j = 0; j < padded_block_len; j++ )
+ {
+ if( j < last_block_len )
+ padded_block[j] = last_block[j];
+ else if( j == last_block_len )
+ padded_block[j] = 0x80;
+ else
+ padded_block[j] = 0x00;
+ }
+}
+
+int mbedcrypto_cipher_cmac_starts( mbedcrypto_cipher_context_t *ctx,
+ const unsigned char *key, size_t keybits )
+{
+ mbedcrypto_cipher_type_t type;
+ mbedcrypto_cmac_context_t *cmac_ctx;
+ int retval;
+
+ if( ctx == NULL || ctx->cipher_info == NULL || key == NULL )
+ return( MBEDCRYPTO_ERR_CIPHER_BAD_INPUT_DATA );
+
+ if( ( retval = mbedcrypto_cipher_setkey( ctx, key, (int)keybits,
+ MBEDCRYPTO_ENCRYPT ) ) != 0 )
+ return( retval );
+
+ type = ctx->cipher_info->type;
+
+ switch( type )
+ {
+ case MBEDCRYPTO_CIPHER_AES_128_ECB:
+ case MBEDCRYPTO_CIPHER_AES_192_ECB:
+ case MBEDCRYPTO_CIPHER_AES_256_ECB:
+ case MBEDCRYPTO_CIPHER_DES_EDE3_ECB:
+ break;
+ default:
+ return( MBEDCRYPTO_ERR_CIPHER_BAD_INPUT_DATA );
+ }
+
+ /* Allocated and initialise in the cipher context memory for the CMAC
+ * context */
+ cmac_ctx = mbedcrypto_calloc( 1, sizeof( mbedcrypto_cmac_context_t ) );
+ if( cmac_ctx == NULL )
+ return( MBEDCRYPTO_ERR_CIPHER_ALLOC_FAILED );
+
+ ctx->cmac_ctx = cmac_ctx;
+
+ mbedcrypto_platform_zeroize( cmac_ctx->state, sizeof( cmac_ctx->state ) );
+
+ return 0;
+}
+
+int mbedcrypto_cipher_cmac_update( mbedcrypto_cipher_context_t *ctx,
+ const unsigned char *input, size_t ilen )
+{
+ mbedcrypto_cmac_context_t* cmac_ctx;
+ unsigned char *state;
+ int ret = 0;
+ size_t n, j, olen, block_size;
+
+ if( ctx == NULL || ctx->cipher_info == NULL || input == NULL ||
+ ctx->cmac_ctx == NULL )
+ return( MBEDCRYPTO_ERR_CIPHER_BAD_INPUT_DATA );
+
+ cmac_ctx = ctx->cmac_ctx;
+ block_size = ctx->cipher_info->block_size;
+ state = ctx->cmac_ctx->state;
+
+ /* Is there data still to process from the last call, that's greater in
+ * size than a block? */
+ if( cmac_ctx->unprocessed_len > 0 &&
+ ilen > block_size - cmac_ctx->unprocessed_len )
+ {
+ memcpy( &cmac_ctx->unprocessed_block[cmac_ctx->unprocessed_len],
+ input,
+ block_size - cmac_ctx->unprocessed_len );
+
+ cmac_xor_block( state, cmac_ctx->unprocessed_block, state, block_size );
+
+ if( ( ret = mbedcrypto_cipher_update( ctx, state, block_size, state,
+ &olen ) ) != 0 )
+ {
+ goto exit;
+ }
+
+ input += block_size - cmac_ctx->unprocessed_len;
+ ilen -= block_size - cmac_ctx->unprocessed_len;
+ cmac_ctx->unprocessed_len = 0;
+ }
+
+ /* n is the number of blocks including any final partial block */
+ n = ( ilen + block_size - 1 ) / block_size;
+
+ /* Iterate across the input data in block sized chunks, excluding any
+ * final partial or complete block */
+ for( j = 1; j < n; j++ )
+ {
+ cmac_xor_block( state, input, state, block_size );
+
+ if( ( ret = mbedcrypto_cipher_update( ctx, state, block_size, state,
+ &olen ) ) != 0 )
+ goto exit;
+
+ ilen -= block_size;
+ input += block_size;
+ }
+
+ /* If there is data left over that wasn't aligned to a block */
+ if( ilen > 0 )
+ {
+ memcpy( &cmac_ctx->unprocessed_block[cmac_ctx->unprocessed_len],
+ input,
+ ilen );
+ cmac_ctx->unprocessed_len += ilen;
+ }
+
+exit:
+ return( ret );
+}
+
+int mbedcrypto_cipher_cmac_finish( mbedcrypto_cipher_context_t *ctx,
+ unsigned char *output )
+{
+ mbedcrypto_cmac_context_t* cmac_ctx;
+ unsigned char *state, *last_block;
+ unsigned char K1[MBEDCRYPTO_CIPHER_BLKSIZE_MAX];
+ unsigned char K2[MBEDCRYPTO_CIPHER_BLKSIZE_MAX];
+ unsigned char M_last[MBEDCRYPTO_CIPHER_BLKSIZE_MAX];
+ int ret;
+ size_t olen, block_size;
+
+ if( ctx == NULL || ctx->cipher_info == NULL || ctx->cmac_ctx == NULL ||
+ output == NULL )
+ return( MBEDCRYPTO_ERR_CIPHER_BAD_INPUT_DATA );
+
+ cmac_ctx = ctx->cmac_ctx;
+ block_size = ctx->cipher_info->block_size;
+ state = cmac_ctx->state;
+
+ mbedcrypto_platform_zeroize( K1, sizeof( K1 ) );
+ mbedcrypto_platform_zeroize( K2, sizeof( K2 ) );
+ cmac_generate_subkeys( ctx, K1, K2 );
+
+ last_block = cmac_ctx->unprocessed_block;
+
+ /* Calculate last block */
+ if( cmac_ctx->unprocessed_len < block_size )
+ {
+ cmac_pad( M_last, block_size, last_block, cmac_ctx->unprocessed_len );
+ cmac_xor_block( M_last, M_last, K2, block_size );
+ }
+ else
+ {
+ /* Last block is complete block */
+ cmac_xor_block( M_last, last_block, K1, block_size );
+ }
+
+
+ cmac_xor_block( state, M_last, state, block_size );
+ if( ( ret = mbedcrypto_cipher_update( ctx, state, block_size, state,
+ &olen ) ) != 0 )
+ {
+ goto exit;
+ }
+
+ memcpy( output, state, block_size );
+
+exit:
+ /* Wipe the generated keys on the stack, and any other transients to avoid
+ * side channel leakage */
+ mbedcrypto_platform_zeroize( K1, sizeof( K1 ) );
+ mbedcrypto_platform_zeroize( K2, sizeof( K2 ) );
+
+ cmac_ctx->unprocessed_len = 0;
+ mbedcrypto_platform_zeroize( cmac_ctx->unprocessed_block,
+ sizeof( cmac_ctx->unprocessed_block ) );
+
+ mbedcrypto_platform_zeroize( state, MBEDCRYPTO_CIPHER_BLKSIZE_MAX );
+ return( ret );
+}
+
+int mbedcrypto_cipher_cmac_reset( mbedcrypto_cipher_context_t *ctx )
+{
+ mbedcrypto_cmac_context_t* cmac_ctx;
+
+ if( ctx == NULL || ctx->cipher_info == NULL || ctx->cmac_ctx == NULL )
+ return( MBEDCRYPTO_ERR_CIPHER_BAD_INPUT_DATA );
+
+ cmac_ctx = ctx->cmac_ctx;
+
+ /* Reset the internal state */
+ cmac_ctx->unprocessed_len = 0;
+ mbedcrypto_platform_zeroize( cmac_ctx->unprocessed_block,
+ sizeof( cmac_ctx->unprocessed_block ) );
+ mbedcrypto_platform_zeroize( cmac_ctx->state,
+ sizeof( cmac_ctx->state ) );
+
+ return( 0 );
+}
+
+int mbedcrypto_cipher_cmac( const mbedcrypto_cipher_info_t *cipher_info,
+ const unsigned char *key, size_t keylen,
+ const unsigned char *input, size_t ilen,
+ unsigned char *output )
+{
+ mbedcrypto_cipher_context_t ctx;
+ int ret;
+
+ if( cipher_info == NULL || key == NULL || input == NULL || output == NULL )
+ return( MBEDCRYPTO_ERR_CIPHER_BAD_INPUT_DATA );
+
+ mbedcrypto_cipher_init( &ctx );
+
+ if( ( ret = mbedcrypto_cipher_setup( &ctx, cipher_info ) ) != 0 )
+ goto exit;
+
+ ret = mbedcrypto_cipher_cmac_starts( &ctx, key, keylen );
+ if( ret != 0 )
+ goto exit;
+
+ ret = mbedcrypto_cipher_cmac_update( &ctx, input, ilen );
+ if( ret != 0 )
+ goto exit;
+
+ ret = mbedcrypto_cipher_cmac_finish( &ctx, output );
+
+exit:
+ mbedcrypto_cipher_free( &ctx );
+
+ return( ret );
+}
+
+#if defined(MBEDCRYPTO_AES_C)
+/*
+ * Implementation of AES-CMAC-PRF-128 defined in RFC 4615
+ */
+int mbedcrypto_aes_cmac_prf_128( const unsigned char *key, size_t key_length,
+ const unsigned char *input, size_t in_len,
+ unsigned char *output )
+{
+ int ret;
+ const mbedcrypto_cipher_info_t *cipher_info;
+ unsigned char zero_key[MBEDCRYPTO_AES_BLOCK_SIZE];
+ unsigned char int_key[MBEDCRYPTO_AES_BLOCK_SIZE];
+
+ if( key == NULL || input == NULL || output == NULL )
+ return( MBEDCRYPTO_ERR_CIPHER_BAD_INPUT_DATA );
+
+ cipher_info = mbedcrypto_cipher_info_from_type( MBEDCRYPTO_CIPHER_AES_128_ECB );
+ if( cipher_info == NULL )
+ {
+ /* Failing at this point must be due to a build issue */
+ ret = MBEDCRYPTO_ERR_CIPHER_FEATURE_UNAVAILABLE;
+ goto exit;
+ }
+
+ if( key_length == MBEDCRYPTO_AES_BLOCK_SIZE )
+ {
+ /* Use key as is */
+ memcpy( int_key, key, MBEDCRYPTO_AES_BLOCK_SIZE );
+ }
+ else
+ {
+ memset( zero_key, 0, MBEDCRYPTO_AES_BLOCK_SIZE );
+
+ ret = mbedcrypto_cipher_cmac( cipher_info, zero_key, 128, key,
+ key_length, int_key );
+ if( ret != 0 )
+ goto exit;
+ }
+
+ ret = mbedcrypto_cipher_cmac( cipher_info, int_key, 128, input, in_len,
+ output );
+
+exit:
+ mbedcrypto_platform_zeroize( int_key, sizeof( int_key ) );
+
+ return( ret );
+}
+#endif /* MBEDCRYPTO_AES_C */
+
+#endif /* !MBEDCRYPTO_CMAC_ALT */
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+/*
+ * CMAC test data for SP800-38B
+ * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/AES_CMAC.pdf
+ * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/TDES_CMAC.pdf
+ *
+ * AES-CMAC-PRF-128 test data from RFC 4615
+ * https://tools.ietf.org/html/rfc4615#page-4
+ */
+
+#define NB_CMAC_TESTS_PER_KEY 4
+#define NB_PRF_TESTS 3
+
+#if defined(MBEDCRYPTO_AES_C) || defined(MBEDCRYPTO_DES_C)
+/* All CMAC test inputs are truncated from the same 64 byte buffer. */
+static const unsigned char test_message[] = {
+ /* PT */
+ 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
+};
+#endif /* MBEDCRYPTO_AES_C || MBEDCRYPTO_DES_C */
+
+#if defined(MBEDCRYPTO_AES_C)
+/* Truncation point of message for AES CMAC tests */
+static const unsigned int aes_message_lengths[NB_CMAC_TESTS_PER_KEY] = {
+ /* Mlen */
+ 0,
+ 16,
+ 20,
+ 64
+};
+
+/* CMAC-AES128 Test Data */
+static const unsigned char aes_128_key[16] = {
+ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
+};
+static const unsigned char aes_128_subkeys[2][MBEDCRYPTO_AES_BLOCK_SIZE] = {
+ {
+ /* K1 */
+ 0xfb, 0xee, 0xd6, 0x18, 0x35, 0x71, 0x33, 0x66,
+ 0x7c, 0x85, 0xe0, 0x8f, 0x72, 0x36, 0xa8, 0xde
+ },
+ {
+ /* K2 */
+ 0xf7, 0xdd, 0xac, 0x30, 0x6a, 0xe2, 0x66, 0xcc,
+ 0xf9, 0x0b, 0xc1, 0x1e, 0xe4, 0x6d, 0x51, 0x3b
+ }
+};
+static const unsigned char aes_128_expected_result[NB_CMAC_TESTS_PER_KEY][MBEDCRYPTO_AES_BLOCK_SIZE] = {
+ {
+ /* Example #1 */
+ 0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28,
+ 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46
+ },
+ {
+ /* Example #2 */
+ 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44,
+ 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c
+ },
+ {
+ /* Example #3 */
+ 0x7d, 0x85, 0x44, 0x9e, 0xa6, 0xea, 0x19, 0xc8,
+ 0x23, 0xa7, 0xbf, 0x78, 0x83, 0x7d, 0xfa, 0xde
+ },
+ {
+ /* Example #4 */
+ 0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92,
+ 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe
+ }
+};
+
+/* CMAC-AES192 Test Data */
+static const unsigned char aes_192_key[24] = {
+ 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52,
+ 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5,
+ 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b
+};
+static const unsigned char aes_192_subkeys[2][MBEDCRYPTO_AES_BLOCK_SIZE] = {
+ {
+ /* K1 */
+ 0x44, 0x8a, 0x5b, 0x1c, 0x93, 0x51, 0x4b, 0x27,
+ 0x3e, 0xe6, 0x43, 0x9d, 0xd4, 0xda, 0xa2, 0x96
+ },
+ {
+ /* K2 */
+ 0x89, 0x14, 0xb6, 0x39, 0x26, 0xa2, 0x96, 0x4e,
+ 0x7d, 0xcc, 0x87, 0x3b, 0xa9, 0xb5, 0x45, 0x2c
+ }
+};
+static const unsigned char aes_192_expected_result[NB_CMAC_TESTS_PER_KEY][MBEDCRYPTO_AES_BLOCK_SIZE] = {
+ {
+ /* Example #1 */
+ 0xd1, 0x7d, 0xdf, 0x46, 0xad, 0xaa, 0xcd, 0xe5,
+ 0x31, 0xca, 0xc4, 0x83, 0xde, 0x7a, 0x93, 0x67
+ },
+ {
+ /* Example #2 */
+ 0x9e, 0x99, 0xa7, 0xbf, 0x31, 0xe7, 0x10, 0x90,
+ 0x06, 0x62, 0xf6, 0x5e, 0x61, 0x7c, 0x51, 0x84
+ },
+ {
+ /* Example #3 */
+ 0x3d, 0x75, 0xc1, 0x94, 0xed, 0x96, 0x07, 0x04,
+ 0x44, 0xa9, 0xfa, 0x7e, 0xc7, 0x40, 0xec, 0xf8
+ },
+ {
+ /* Example #4 */
+ 0xa1, 0xd5, 0xdf, 0x0e, 0xed, 0x79, 0x0f, 0x79,
+ 0x4d, 0x77, 0x58, 0x96, 0x59, 0xf3, 0x9a, 0x11
+ }
+};
+
+/* CMAC-AES256 Test Data */
+static const unsigned char aes_256_key[32] = {
+ 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_256_subkeys[2][MBEDCRYPTO_AES_BLOCK_SIZE] = {
+ {
+ /* K1 */
+ 0xca, 0xd1, 0xed, 0x03, 0x29, 0x9e, 0xed, 0xac,
+ 0x2e, 0x9a, 0x99, 0x80, 0x86, 0x21, 0x50, 0x2f
+ },
+ {
+ /* K2 */
+ 0x95, 0xa3, 0xda, 0x06, 0x53, 0x3d, 0xdb, 0x58,
+ 0x5d, 0x35, 0x33, 0x01, 0x0c, 0x42, 0xa0, 0xd9
+ }
+};
+static const unsigned char aes_256_expected_result[NB_CMAC_TESTS_PER_KEY][MBEDCRYPTO_AES_BLOCK_SIZE] = {
+ {
+ /* Example #1 */
+ 0x02, 0x89, 0x62, 0xf6, 0x1b, 0x7b, 0xf8, 0x9e,
+ 0xfc, 0x6b, 0x55, 0x1f, 0x46, 0x67, 0xd9, 0x83
+ },
+ {
+ /* Example #2 */
+ 0x28, 0xa7, 0x02, 0x3f, 0x45, 0x2e, 0x8f, 0x82,
+ 0xbd, 0x4b, 0xf2, 0x8d, 0x8c, 0x37, 0xc3, 0x5c
+ },
+ {
+ /* Example #3 */
+ 0x15, 0x67, 0x27, 0xdc, 0x08, 0x78, 0x94, 0x4a,
+ 0x02, 0x3c, 0x1f, 0xe0, 0x3b, 0xad, 0x6d, 0x93
+ },
+ {
+ /* Example #4 */
+ 0xe1, 0x99, 0x21, 0x90, 0x54, 0x9f, 0x6e, 0xd5,
+ 0x69, 0x6a, 0x2c, 0x05, 0x6c, 0x31, 0x54, 0x10
+ }
+};
+#endif /* MBEDCRYPTO_AES_C */
+
+#if defined(MBEDCRYPTO_DES_C)
+/* Truncation point of message for 3DES CMAC tests */
+static const unsigned int des3_message_lengths[NB_CMAC_TESTS_PER_KEY] = {
+ 0,
+ 16,
+ 20,
+ 32
+};
+
+/* CMAC-TDES (Generation) - 2 Key Test Data */
+static const unsigned char des3_2key_key[24] = {
+ /* Key1 */
+ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+ /* Key2 */
+ 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xEF, 0x01,
+ /* Key3 */
+ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef
+};
+static const unsigned char des3_2key_subkeys[2][8] = {
+ {
+ /* K1 */
+ 0x0d, 0xd2, 0xcb, 0x7a, 0x3d, 0x88, 0x88, 0xd9
+ },
+ {
+ /* K2 */
+ 0x1b, 0xa5, 0x96, 0xf4, 0x7b, 0x11, 0x11, 0xb2
+ }
+};
+static const unsigned char des3_2key_expected_result[NB_CMAC_TESTS_PER_KEY][MBEDCRYPTO_DES3_BLOCK_SIZE] = {
+ {
+ /* Sample #1 */
+ 0x79, 0xce, 0x52, 0xa7, 0xf7, 0x86, 0xa9, 0x60
+ },
+ {
+ /* Sample #2 */
+ 0xcc, 0x18, 0xa0, 0xb7, 0x9a, 0xf2, 0x41, 0x3b
+ },
+ {
+ /* Sample #3 */
+ 0xc0, 0x6d, 0x37, 0x7e, 0xcd, 0x10, 0x19, 0x69
+ },
+ {
+ /* Sample #4 */
+ 0x9c, 0xd3, 0x35, 0x80, 0xf9, 0xb6, 0x4d, 0xfb
+ }
+};
+
+/* CMAC-TDES (Generation) - 3 Key Test Data */
+static const unsigned char des3_3key_key[24] = {
+ /* Key1 */
+ 0x01, 0x23, 0x45, 0x67, 0x89, 0xaa, 0xcd, 0xef,
+ /* Key2 */
+ 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01,
+ /* Key3 */
+ 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23
+};
+static const unsigned char des3_3key_subkeys[2][8] = {
+ {
+ /* K1 */
+ 0x9d, 0x74, 0xe7, 0x39, 0x33, 0x17, 0x96, 0xc0
+ },
+ {
+ /* K2 */
+ 0x3a, 0xe9, 0xce, 0x72, 0x66, 0x2f, 0x2d, 0x9b
+ }
+};
+static const unsigned char des3_3key_expected_result[NB_CMAC_TESTS_PER_KEY][MBEDCRYPTO_DES3_BLOCK_SIZE] = {
+ {
+ /* Sample #1 */
+ 0x7d, 0xb0, 0xd3, 0x7d, 0xf9, 0x36, 0xc5, 0x50
+ },
+ {
+ /* Sample #2 */
+ 0x30, 0x23, 0x9c, 0xf1, 0xf5, 0x2e, 0x66, 0x09
+ },
+ {
+ /* Sample #3 */
+ 0x6c, 0x9f, 0x3e, 0xe4, 0x92, 0x3f, 0x6b, 0xe2
+ },
+ {
+ /* Sample #4 */
+ 0x99, 0x42, 0x9b, 0xd0, 0xbF, 0x79, 0x04, 0xe5
+ }
+};
+
+#endif /* MBEDCRYPTO_DES_C */
+
+#if defined(MBEDCRYPTO_AES_C)
+/* AES AES-CMAC-PRF-128 Test Data */
+static const unsigned char PRFK[] = {
+ /* Key */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0xed, 0xcb
+};
+
+/* Sizes in bytes */
+static const size_t PRFKlen[NB_PRF_TESTS] = {
+ 18,
+ 16,
+ 10
+};
+
+/* Message */
+static const unsigned char PRFM[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13
+};
+
+static const unsigned char PRFT[NB_PRF_TESTS][16] = {
+ {
+ 0x84, 0xa3, 0x48, 0xa4, 0xa4, 0x5d, 0x23, 0x5b,
+ 0xab, 0xff, 0xfc, 0x0d, 0x2b, 0x4d, 0xa0, 0x9a
+ },
+ {
+ 0x98, 0x0a, 0xe8, 0x7b, 0x5f, 0x4c, 0x9c, 0x52,
+ 0x14, 0xf5, 0xb6, 0xa8, 0x45, 0x5e, 0x4c, 0x2d
+ },
+ {
+ 0x29, 0x0d, 0x9e, 0x11, 0x2e, 0xdb, 0x09, 0xee,
+ 0x14, 0x1f, 0xcf, 0x64, 0xc0, 0xb7, 0x2f, 0x3d
+ }
+};
+#endif /* MBEDCRYPTO_AES_C */
+
+static int cmac_test_subkeys( int verbose,
+ const char* testname,
+ const unsigned char* key,
+ int keybits,
+ const unsigned char* subkeys,
+ mbedcrypto_cipher_type_t cipher_type,
+ int block_size,
+ int num_tests )
+{
+ int i, ret = 0;
+ mbedcrypto_cipher_context_t ctx;
+ const mbedcrypto_cipher_info_t *cipher_info;
+ unsigned char K1[MBEDCRYPTO_CIPHER_BLKSIZE_MAX];
+ unsigned char K2[MBEDCRYPTO_CIPHER_BLKSIZE_MAX];
+
+ cipher_info = mbedcrypto_cipher_info_from_type( cipher_type );
+ if( cipher_info == NULL )
+ {
+ /* Failing at this point must be due to a build issue */
+ return( MBEDCRYPTO_ERR_CIPHER_FEATURE_UNAVAILABLE );
+ }
+
+ for( i = 0; i < num_tests; i++ )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( " %s CMAC subkey #%u: ", testname, i + 1 );
+
+ mbedcrypto_cipher_init( &ctx );
+
+ if( ( ret = mbedcrypto_cipher_setup( &ctx, cipher_info ) ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( "test execution failed\n" );
+
+ goto cleanup;
+ }
+
+ if( ( ret = mbedcrypto_cipher_setkey( &ctx, key, keybits,
+ MBEDCRYPTO_ENCRYPT ) ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( "test execution failed\n" );
+
+ goto cleanup;
+ }
+
+ ret = cmac_generate_subkeys( &ctx, K1, K2 );
+ if( ret != 0 )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+
+ goto cleanup;
+ }
+
+ if( ( ret = memcmp( K1, subkeys, block_size ) ) != 0 ||
+ ( ret = memcmp( K2, &subkeys[block_size], block_size ) ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+
+ goto cleanup;
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+
+ mbedcrypto_cipher_free( &ctx );
+ }
+
+ goto exit;
+
+cleanup:
+ mbedcrypto_cipher_free( &ctx );
+
+exit:
+ return( ret );
+}
+
+static int cmac_test_wth_cipher( int verbose,
+ const char* testname,
+ const unsigned char* key,
+ int keybits,
+ const unsigned char* messages,
+ const unsigned int message_lengths[4],
+ const unsigned char* expected_result,
+ mbedcrypto_cipher_type_t cipher_type,
+ int block_size,
+ int num_tests )
+{
+ const mbedcrypto_cipher_info_t *cipher_info;
+ int i, ret = 0;
+ unsigned char output[MBEDCRYPTO_CIPHER_BLKSIZE_MAX];
+
+ cipher_info = mbedcrypto_cipher_info_from_type( cipher_type );
+ if( cipher_info == NULL )
+ {
+ /* Failing at this point must be due to a build issue */
+ ret = MBEDCRYPTO_ERR_CIPHER_FEATURE_UNAVAILABLE;
+ goto exit;
+ }
+
+ for( i = 0; i < num_tests; i++ )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( " %s CMAC #%u: ", testname, i + 1 );
+
+ if( ( ret = mbedcrypto_cipher_cmac( cipher_info, key, keybits, messages,
+ message_lengths[i], output ) ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+ goto exit;
+ }
+
+ if( ( ret = memcmp( output, &expected_result[i * block_size], block_size ) ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+ goto exit;
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+ }
+
+exit:
+ return( ret );
+}
+
+#if defined(MBEDCRYPTO_AES_C)
+static int test_aes128_cmac_prf( int verbose )
+{
+ int i;
+ int ret;
+ unsigned char output[MBEDCRYPTO_AES_BLOCK_SIZE];
+
+ for( i = 0; i < NB_PRF_TESTS; i++ )
+ {
+ mbedcrypto_printf( " AES CMAC 128 PRF #%u: ", i );
+ ret = mbedcrypto_aes_cmac_prf_128( PRFK, PRFKlen[i], PRFM, 20, output );
+ if( ret != 0 ||
+ memcmp( output, PRFT[i], MBEDCRYPTO_AES_BLOCK_SIZE ) != 0 )
+ {
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+
+ return( ret );
+ }
+ else if( verbose != 0 )
+ {
+ mbedcrypto_printf( "passed\n" );
+ }
+ }
+ return( ret );
+}
+#endif /* MBEDCRYPTO_AES_C */
+
+int mbedcrypto_cmac_self_test( int verbose )
+{
+ int ret;
+
+#if defined(MBEDCRYPTO_AES_C)
+ /* AES-128 */
+ if( ( ret = cmac_test_subkeys( verbose,
+ "AES 128",
+ aes_128_key,
+ 128,
+ (const unsigned char*)aes_128_subkeys,
+ MBEDCRYPTO_CIPHER_AES_128_ECB,
+ MBEDCRYPTO_AES_BLOCK_SIZE,
+ NB_CMAC_TESTS_PER_KEY ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ if( ( ret = cmac_test_wth_cipher( verbose,
+ "AES 128",
+ aes_128_key,
+ 128,
+ test_message,
+ aes_message_lengths,
+ (const unsigned char*)aes_128_expected_result,
+ MBEDCRYPTO_CIPHER_AES_128_ECB,
+ MBEDCRYPTO_AES_BLOCK_SIZE,
+ NB_CMAC_TESTS_PER_KEY ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ /* AES-192 */
+ if( ( ret = cmac_test_subkeys( verbose,
+ "AES 192",
+ aes_192_key,
+ 192,
+ (const unsigned char*)aes_192_subkeys,
+ MBEDCRYPTO_CIPHER_AES_192_ECB,
+ MBEDCRYPTO_AES_BLOCK_SIZE,
+ NB_CMAC_TESTS_PER_KEY ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ if( ( ret = cmac_test_wth_cipher( verbose,
+ "AES 192",
+ aes_192_key,
+ 192,
+ test_message,
+ aes_message_lengths,
+ (const unsigned char*)aes_192_expected_result,
+ MBEDCRYPTO_CIPHER_AES_192_ECB,
+ MBEDCRYPTO_AES_BLOCK_SIZE,
+ NB_CMAC_TESTS_PER_KEY ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ /* AES-256 */
+ if( ( ret = cmac_test_subkeys( verbose,
+ "AES 256",
+ aes_256_key,
+ 256,
+ (const unsigned char*)aes_256_subkeys,
+ MBEDCRYPTO_CIPHER_AES_256_ECB,
+ MBEDCRYPTO_AES_BLOCK_SIZE,
+ NB_CMAC_TESTS_PER_KEY ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ if( ( ret = cmac_test_wth_cipher ( verbose,
+ "AES 256",
+ aes_256_key,
+ 256,
+ test_message,
+ aes_message_lengths,
+ (const unsigned char*)aes_256_expected_result,
+ MBEDCRYPTO_CIPHER_AES_256_ECB,
+ MBEDCRYPTO_AES_BLOCK_SIZE,
+ NB_CMAC_TESTS_PER_KEY ) ) != 0 )
+ {
+ return( ret );
+ }
+#endif /* MBEDCRYPTO_AES_C */
+
+#if defined(MBEDCRYPTO_DES_C)
+ /* 3DES 2 key */
+ if( ( ret = cmac_test_subkeys( verbose,
+ "3DES 2 key",
+ des3_2key_key,
+ 192,
+ (const unsigned char*)des3_2key_subkeys,
+ MBEDCRYPTO_CIPHER_DES_EDE3_ECB,
+ MBEDCRYPTO_DES3_BLOCK_SIZE,
+ NB_CMAC_TESTS_PER_KEY ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ if( ( ret = cmac_test_wth_cipher( verbose,
+ "3DES 2 key",
+ des3_2key_key,
+ 192,
+ test_message,
+ des3_message_lengths,
+ (const unsigned char*)des3_2key_expected_result,
+ MBEDCRYPTO_CIPHER_DES_EDE3_ECB,
+ MBEDCRYPTO_DES3_BLOCK_SIZE,
+ NB_CMAC_TESTS_PER_KEY ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ /* 3DES 3 key */
+ if( ( ret = cmac_test_subkeys( verbose,
+ "3DES 3 key",
+ des3_3key_key,
+ 192,
+ (const unsigned char*)des3_3key_subkeys,
+ MBEDCRYPTO_CIPHER_DES_EDE3_ECB,
+ MBEDCRYPTO_DES3_BLOCK_SIZE,
+ NB_CMAC_TESTS_PER_KEY ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ if( ( ret = cmac_test_wth_cipher( verbose,
+ "3DES 3 key",
+ des3_3key_key,
+ 192,
+ test_message,
+ des3_message_lengths,
+ (const unsigned char*)des3_3key_expected_result,
+ MBEDCRYPTO_CIPHER_DES_EDE3_ECB,
+ MBEDCRYPTO_DES3_BLOCK_SIZE,
+ NB_CMAC_TESTS_PER_KEY ) ) != 0 )
+ {
+ return( ret );
+ }
+#endif /* MBEDCRYPTO_DES_C */
+
+#if defined(MBEDCRYPTO_AES_C)
+ if( ( ret = test_aes128_cmac_prf( verbose ) ) != 0 )
+ return( ret );
+#endif /* MBEDCRYPTO_AES_C */
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "\n" );
+
+ return( 0 );
+}
+
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#endif /* MBEDCRYPTO_CMAC_C */
diff --git a/library/ctr_drbg.c b/library/ctr_drbg.c
new file mode 100644
index 0000000..36ea251
--- /dev/null
+++ b/library/ctr_drbg.c
@@ -0,0 +1,650 @@
+/*
+ * CTR_DRBG implementation based on AES-256 (NIST SP 800-90)
+ *
+ * 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 Crypto (https://tls.mbed.org)
+ */
+/*
+ * The NIST SP 800-90 DRBGs are described in the following publication.
+ *
+ * http://csrc.nist.gov/publications/nistpubs/800-90/SP800-90revised_March2007.pdf
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_CTR_DRBG_C)
+
+#include "mbedcrypto/ctr_drbg.h"
+#include "mbedcrypto/platform_util.h"
+
+#include <string.h>
+
+#if defined(MBEDCRYPTO_FS_IO)
+#include <stdio.h>
+#endif
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#include <stdio.h>
+#define mbedcrypto_printf printf
+#endif /* MBEDCRYPTO_PLATFORM_C */
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+/*
+ * CTR_DRBG context initialization
+ */
+void mbedcrypto_ctr_drbg_init( mbedcrypto_ctr_drbg_context *ctx )
+{
+ memset( ctx, 0, sizeof( mbedcrypto_ctr_drbg_context ) );
+
+#if defined(MBEDCRYPTO_THREADING_C)
+ mbedcrypto_mutex_init( &ctx->mutex );
+#endif
+}
+
+/*
+ * Non-public function wrapped by mbedcrypto_ctr_drbg_seed(). Necessary to allow
+ * NIST tests to succeed (which require known length fixed entropy)
+ */
+int mbedcrypto_ctr_drbg_seed_entropy_len(
+ mbedcrypto_ctr_drbg_context *ctx,
+ int (*f_entropy)(void *, unsigned char *, size_t),
+ void *p_entropy,
+ const unsigned char *custom,
+ size_t len,
+ size_t entropy_len )
+{
+ int ret;
+ unsigned char key[MBEDCRYPTO_CTR_DRBG_KEYSIZE];
+
+ memset( key, 0, MBEDCRYPTO_CTR_DRBG_KEYSIZE );
+
+ mbedcrypto_aes_init( &ctx->aes_ctx );
+
+ ctx->f_entropy = f_entropy;
+ ctx->p_entropy = p_entropy;
+
+ ctx->entropy_len = entropy_len;
+ ctx->reseed_interval = MBEDCRYPTO_CTR_DRBG_RESEED_INTERVAL;
+
+ /*
+ * Initialize with an empty key
+ */
+ if( ( ret = mbedcrypto_aes_setkey_enc( &ctx->aes_ctx, key, MBEDCRYPTO_CTR_DRBG_KEYBITS ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ if( ( ret = mbedcrypto_ctr_drbg_reseed( ctx, custom, len ) ) != 0 )
+ {
+ return( ret );
+ }
+ return( 0 );
+}
+
+int mbedcrypto_ctr_drbg_seed( mbedcrypto_ctr_drbg_context *ctx,
+ int (*f_entropy)(void *, unsigned char *, size_t),
+ void *p_entropy,
+ const unsigned char *custom,
+ size_t len )
+{
+ return( mbedcrypto_ctr_drbg_seed_entropy_len( ctx, f_entropy, p_entropy, custom, len,
+ MBEDCRYPTO_CTR_DRBG_ENTROPY_LEN ) );
+}
+
+void mbedcrypto_ctr_drbg_free( mbedcrypto_ctr_drbg_context *ctx )
+{
+ if( ctx == NULL )
+ return;
+
+#if defined(MBEDCRYPTO_THREADING_C)
+ mbedcrypto_mutex_free( &ctx->mutex );
+#endif
+ mbedcrypto_aes_free( &ctx->aes_ctx );
+ mbedcrypto_platform_zeroize( ctx, sizeof( mbedcrypto_ctr_drbg_context ) );
+}
+
+void mbedcrypto_ctr_drbg_set_prediction_resistance( mbedcrypto_ctr_drbg_context *ctx, int resistance )
+{
+ ctx->prediction_resistance = resistance;
+}
+
+void mbedcrypto_ctr_drbg_set_entropy_len( mbedcrypto_ctr_drbg_context *ctx, size_t len )
+{
+ ctx->entropy_len = len;
+}
+
+void mbedcrypto_ctr_drbg_set_reseed_interval( mbedcrypto_ctr_drbg_context *ctx, int interval )
+{
+ ctx->reseed_interval = interval;
+}
+
+static int block_cipher_df( unsigned char *output,
+ const unsigned char *data, size_t data_len )
+{
+ unsigned char buf[MBEDCRYPTO_CTR_DRBG_MAX_SEED_INPUT + MBEDCRYPTO_CTR_DRBG_BLOCKSIZE + 16];
+ unsigned char tmp[MBEDCRYPTO_CTR_DRBG_SEEDLEN];
+ unsigned char key[MBEDCRYPTO_CTR_DRBG_KEYSIZE];
+ unsigned char chain[MBEDCRYPTO_CTR_DRBG_BLOCKSIZE];
+ unsigned char *p, *iv;
+ mbedcrypto_aes_context aes_ctx;
+ int ret = 0;
+
+ int i, j;
+ size_t buf_len, use_len;
+
+ if( data_len > MBEDCRYPTO_CTR_DRBG_MAX_SEED_INPUT )
+ return( MBEDCRYPTO_ERR_CTR_DRBG_INPUT_TOO_BIG );
+
+ memset( buf, 0, MBEDCRYPTO_CTR_DRBG_MAX_SEED_INPUT + MBEDCRYPTO_CTR_DRBG_BLOCKSIZE + 16 );
+ mbedcrypto_aes_init( &aes_ctx );
+
+ /*
+ * Construct IV (16 bytes) and S in buffer
+ * IV = Counter (in 32-bits) padded to 16 with zeroes
+ * S = Length input string (in 32-bits) || Length of output (in 32-bits) ||
+ * data || 0x80
+ * (Total is padded to a multiple of 16-bytes with zeroes)
+ */
+ p = buf + MBEDCRYPTO_CTR_DRBG_BLOCKSIZE;
+ *p++ = ( data_len >> 24 ) & 0xff;
+ *p++ = ( data_len >> 16 ) & 0xff;
+ *p++ = ( data_len >> 8 ) & 0xff;
+ *p++ = ( data_len ) & 0xff;
+ p += 3;
+ *p++ = MBEDCRYPTO_CTR_DRBG_SEEDLEN;
+ memcpy( p, data, data_len );
+ p[data_len] = 0x80;
+
+ buf_len = MBEDCRYPTO_CTR_DRBG_BLOCKSIZE + 8 + data_len + 1;
+
+ for( i = 0; i < MBEDCRYPTO_CTR_DRBG_KEYSIZE; i++ )
+ key[i] = i;
+
+ if( ( ret = mbedcrypto_aes_setkey_enc( &aes_ctx, key, MBEDCRYPTO_CTR_DRBG_KEYBITS ) ) != 0 )
+ {
+ goto exit;
+ }
+
+ /*
+ * Reduce data to MBEDCRYPTO_CTR_DRBG_SEEDLEN bytes of data
+ */
+ for( j = 0; j < MBEDCRYPTO_CTR_DRBG_SEEDLEN; j += MBEDCRYPTO_CTR_DRBG_BLOCKSIZE )
+ {
+ p = buf;
+ memset( chain, 0, MBEDCRYPTO_CTR_DRBG_BLOCKSIZE );
+ use_len = buf_len;
+
+ while( use_len > 0 )
+ {
+ for( i = 0; i < MBEDCRYPTO_CTR_DRBG_BLOCKSIZE; i++ )
+ chain[i] ^= p[i];
+ p += MBEDCRYPTO_CTR_DRBG_BLOCKSIZE;
+ use_len -= ( use_len >= MBEDCRYPTO_CTR_DRBG_BLOCKSIZE ) ?
+ MBEDCRYPTO_CTR_DRBG_BLOCKSIZE : use_len;
+
+ if( ( ret = mbedcrypto_aes_crypt_ecb( &aes_ctx, MBEDCRYPTO_AES_ENCRYPT, chain, chain ) ) != 0 )
+ {
+ goto exit;
+ }
+ }
+
+ memcpy( tmp + j, chain, MBEDCRYPTO_CTR_DRBG_BLOCKSIZE );
+
+ /*
+ * Update IV
+ */
+ buf[3]++;
+ }
+
+ /*
+ * Do final encryption with reduced data
+ */
+ if( ( ret = mbedcrypto_aes_setkey_enc( &aes_ctx, tmp, MBEDCRYPTO_CTR_DRBG_KEYBITS ) ) != 0 )
+ {
+ goto exit;
+ }
+ iv = tmp + MBEDCRYPTO_CTR_DRBG_KEYSIZE;
+ p = output;
+
+ for( j = 0; j < MBEDCRYPTO_CTR_DRBG_SEEDLEN; j += MBEDCRYPTO_CTR_DRBG_BLOCKSIZE )
+ {
+ if( ( ret = mbedcrypto_aes_crypt_ecb( &aes_ctx, MBEDCRYPTO_AES_ENCRYPT, iv, iv ) ) != 0 )
+ {
+ goto exit;
+ }
+ memcpy( p, iv, MBEDCRYPTO_CTR_DRBG_BLOCKSIZE );
+ p += MBEDCRYPTO_CTR_DRBG_BLOCKSIZE;
+ }
+exit:
+ mbedcrypto_aes_free( &aes_ctx );
+ /*
+ * tidy up the stack
+ */
+ mbedcrypto_platform_zeroize( buf, sizeof( buf ) );
+ mbedcrypto_platform_zeroize( tmp, sizeof( tmp ) );
+ mbedcrypto_platform_zeroize( key, sizeof( key ) );
+ mbedcrypto_platform_zeroize( chain, sizeof( chain ) );
+ if( 0 != ret )
+ {
+ /*
+ * wipe partial seed from memory
+ */
+ mbedcrypto_platform_zeroize( output, MBEDCRYPTO_CTR_DRBG_SEEDLEN );
+ }
+
+ return( ret );
+}
+
+static int ctr_drbg_update_internal( mbedcrypto_ctr_drbg_context *ctx,
+ const unsigned char data[MBEDCRYPTO_CTR_DRBG_SEEDLEN] )
+{
+ unsigned char tmp[MBEDCRYPTO_CTR_DRBG_SEEDLEN];
+ unsigned char *p = tmp;
+ int i, j;
+ int ret = 0;
+
+ memset( tmp, 0, MBEDCRYPTO_CTR_DRBG_SEEDLEN );
+
+ for( j = 0; j < MBEDCRYPTO_CTR_DRBG_SEEDLEN; j += MBEDCRYPTO_CTR_DRBG_BLOCKSIZE )
+ {
+ /*
+ * Increase counter
+ */
+ for( i = MBEDCRYPTO_CTR_DRBG_BLOCKSIZE; i > 0; i-- )
+ if( ++ctx->counter[i - 1] != 0 )
+ break;
+
+ /*
+ * Crypt counter block
+ */
+ if( ( ret = mbedcrypto_aes_crypt_ecb( &ctx->aes_ctx, MBEDCRYPTO_AES_ENCRYPT, ctx->counter, p ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ p += MBEDCRYPTO_CTR_DRBG_BLOCKSIZE;
+ }
+
+ for( i = 0; i < MBEDCRYPTO_CTR_DRBG_SEEDLEN; i++ )
+ tmp[i] ^= data[i];
+
+ /*
+ * Update key and counter
+ */
+ if( ( ret = mbedcrypto_aes_setkey_enc( &ctx->aes_ctx, tmp, MBEDCRYPTO_CTR_DRBG_KEYBITS ) ) != 0 )
+ {
+ return( ret );
+ }
+ memcpy( ctx->counter, tmp + MBEDCRYPTO_CTR_DRBG_KEYSIZE, MBEDCRYPTO_CTR_DRBG_BLOCKSIZE );
+
+ return( 0 );
+}
+
+void mbedcrypto_ctr_drbg_update( mbedcrypto_ctr_drbg_context *ctx,
+ const unsigned char *additional, size_t add_len )
+{
+ unsigned char add_input[MBEDCRYPTO_CTR_DRBG_SEEDLEN];
+
+ if( add_len > 0 )
+ {
+ /* MAX_INPUT would be more logical here, but we have to match
+ * block_cipher_df()'s limits since we can't propagate errors */
+ if( add_len > MBEDCRYPTO_CTR_DRBG_MAX_SEED_INPUT )
+ add_len = MBEDCRYPTO_CTR_DRBG_MAX_SEED_INPUT;
+
+ block_cipher_df( add_input, additional, add_len );
+ ctr_drbg_update_internal( ctx, add_input );
+ }
+}
+
+int mbedcrypto_ctr_drbg_reseed( mbedcrypto_ctr_drbg_context *ctx,
+ const unsigned char *additional, size_t len )
+{
+ unsigned char seed[MBEDCRYPTO_CTR_DRBG_MAX_SEED_INPUT];
+ size_t seedlen = 0;
+ int ret;
+
+ if( ctx->entropy_len > MBEDCRYPTO_CTR_DRBG_MAX_SEED_INPUT ||
+ len > MBEDCRYPTO_CTR_DRBG_MAX_SEED_INPUT - ctx->entropy_len )
+ return( MBEDCRYPTO_ERR_CTR_DRBG_INPUT_TOO_BIG );
+
+ memset( seed, 0, MBEDCRYPTO_CTR_DRBG_MAX_SEED_INPUT );
+
+ /*
+ * Gather entropy_len bytes of entropy to seed state
+ */
+ if( 0 != ctx->f_entropy( ctx->p_entropy, seed,
+ ctx->entropy_len ) )
+ {
+ return( MBEDCRYPTO_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED );
+ }
+
+ seedlen += ctx->entropy_len;
+
+ /*
+ * Add additional data
+ */
+ if( additional && len )
+ {
+ memcpy( seed + seedlen, additional, len );
+ seedlen += len;
+ }
+
+ /*
+ * Reduce to 384 bits
+ */
+ if( ( ret = block_cipher_df( seed, seed, seedlen ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ /*
+ * Update state
+ */
+ if( ( ret = ctr_drbg_update_internal( ctx, seed ) ) != 0 )
+ {
+ return( ret );
+ }
+ ctx->reseed_counter = 1;
+
+ return( 0 );
+}
+
+int mbedcrypto_ctr_drbg_random_with_add( void *p_rng,
+ unsigned char *output, size_t output_len,
+ const unsigned char *additional, size_t add_len )
+{
+ int ret = 0;
+ mbedcrypto_ctr_drbg_context *ctx = (mbedcrypto_ctr_drbg_context *) p_rng;
+ unsigned char add_input[MBEDCRYPTO_CTR_DRBG_SEEDLEN];
+ unsigned char *p = output;
+ unsigned char tmp[MBEDCRYPTO_CTR_DRBG_BLOCKSIZE];
+ int i;
+ size_t use_len;
+
+ if( output_len > MBEDCRYPTO_CTR_DRBG_MAX_REQUEST )
+ return( MBEDCRYPTO_ERR_CTR_DRBG_REQUEST_TOO_BIG );
+
+ if( add_len > MBEDCRYPTO_CTR_DRBG_MAX_INPUT )
+ return( MBEDCRYPTO_ERR_CTR_DRBG_INPUT_TOO_BIG );
+
+ memset( add_input, 0, MBEDCRYPTO_CTR_DRBG_SEEDLEN );
+
+ if( ctx->reseed_counter > ctx->reseed_interval ||
+ ctx->prediction_resistance )
+ {
+ if( ( ret = mbedcrypto_ctr_drbg_reseed( ctx, additional, add_len ) ) != 0 )
+ {
+ return( ret );
+ }
+ add_len = 0;
+ }
+
+ if( add_len > 0 )
+ {
+ if( ( ret = block_cipher_df( add_input, additional, add_len ) ) != 0 )
+ {
+ return( ret );
+ }
+ if( ( ret = ctr_drbg_update_internal( ctx, add_input ) ) != 0 )
+ {
+ return( ret );
+ }
+ }
+
+ while( output_len > 0 )
+ {
+ /*
+ * Increase counter
+ */
+ for( i = MBEDCRYPTO_CTR_DRBG_BLOCKSIZE; i > 0; i-- )
+ if( ++ctx->counter[i - 1] != 0 )
+ break;
+
+ /*
+ * Crypt counter block
+ */
+ if( ( ret = mbedcrypto_aes_crypt_ecb( &ctx->aes_ctx, MBEDCRYPTO_AES_ENCRYPT, ctx->counter, tmp ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ use_len = ( output_len > MBEDCRYPTO_CTR_DRBG_BLOCKSIZE ) ? MBEDCRYPTO_CTR_DRBG_BLOCKSIZE :
+ output_len;
+ /*
+ * Copy random block to destination
+ */
+ memcpy( p, tmp, use_len );
+ p += use_len;
+ output_len -= use_len;
+ }
+
+ if( ( ret = ctr_drbg_update_internal( ctx, add_input ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ ctx->reseed_counter++;
+
+ return( 0 );
+}
+
+int mbedcrypto_ctr_drbg_random( void *p_rng, unsigned char *output, size_t output_len )
+{
+ int ret;
+ mbedcrypto_ctr_drbg_context *ctx = (mbedcrypto_ctr_drbg_context *) p_rng;
+
+#if defined(MBEDCRYPTO_THREADING_C)
+ if( ( ret = mbedcrypto_mutex_lock( &ctx->mutex ) ) != 0 )
+ return( ret );
+#endif
+
+ ret = mbedcrypto_ctr_drbg_random_with_add( ctx, output, output_len, NULL, 0 );
+
+#if defined(MBEDCRYPTO_THREADING_C)
+ if( mbedcrypto_mutex_unlock( &ctx->mutex ) != 0 )
+ return( MBEDCRYPTO_ERR_THREADING_MUTEX_ERROR );
+#endif
+
+ return( ret );
+}
+
+#if defined(MBEDCRYPTO_FS_IO)
+int mbedcrypto_ctr_drbg_write_seed_file( mbedcrypto_ctr_drbg_context *ctx, const char *path )
+{
+ int ret = MBEDCRYPTO_ERR_CTR_DRBG_FILE_IO_ERROR;
+ FILE *f;
+ unsigned char buf[ MBEDCRYPTO_CTR_DRBG_MAX_INPUT ];
+
+ if( ( f = fopen( path, "wb" ) ) == NULL )
+ return( MBEDCRYPTO_ERR_CTR_DRBG_FILE_IO_ERROR );
+
+ if( ( ret = mbedcrypto_ctr_drbg_random( ctx, buf, MBEDCRYPTO_CTR_DRBG_MAX_INPUT ) ) != 0 )
+ goto exit;
+
+ if( fwrite( buf, 1, MBEDCRYPTO_CTR_DRBG_MAX_INPUT, f ) != MBEDCRYPTO_CTR_DRBG_MAX_INPUT )
+ ret = MBEDCRYPTO_ERR_CTR_DRBG_FILE_IO_ERROR;
+ else
+ ret = 0;
+
+exit:
+ mbedcrypto_platform_zeroize( buf, sizeof( buf ) );
+
+ fclose( f );
+ return( ret );
+}
+
+int mbedcrypto_ctr_drbg_update_seed_file( mbedcrypto_ctr_drbg_context *ctx, const char *path )
+{
+ int ret = 0;
+ FILE *f;
+ size_t n;
+ unsigned char buf[ MBEDCRYPTO_CTR_DRBG_MAX_INPUT ];
+
+ if( ( f = fopen( path, "rb" ) ) == NULL )
+ return( MBEDCRYPTO_ERR_CTR_DRBG_FILE_IO_ERROR );
+
+ fseek( f, 0, SEEK_END );
+ n = (size_t) ftell( f );
+ fseek( f, 0, SEEK_SET );
+
+ if( n > MBEDCRYPTO_CTR_DRBG_MAX_INPUT )
+ {
+ fclose( f );
+ return( MBEDCRYPTO_ERR_CTR_DRBG_INPUT_TOO_BIG );
+ }
+
+ if( fread( buf, 1, n, f ) != n )
+ ret = MBEDCRYPTO_ERR_CTR_DRBG_FILE_IO_ERROR;
+ else
+ mbedcrypto_ctr_drbg_update( ctx, buf, n );
+
+ fclose( f );
+
+ mbedcrypto_platform_zeroize( buf, sizeof( buf ) );
+
+ if( ret != 0 )
+ return( ret );
+
+ return( mbedcrypto_ctr_drbg_write_seed_file( ctx, path ) );
+}
+#endif /* MBEDCRYPTO_FS_IO */
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+
+static const unsigned char entropy_source_pr[96] =
+ { 0xc1, 0x80, 0x81, 0xa6, 0x5d, 0x44, 0x02, 0x16,
+ 0x19, 0xb3, 0xf1, 0x80, 0xb1, 0xc9, 0x20, 0x02,
+ 0x6a, 0x54, 0x6f, 0x0c, 0x70, 0x81, 0x49, 0x8b,
+ 0x6e, 0xa6, 0x62, 0x52, 0x6d, 0x51, 0xb1, 0xcb,
+ 0x58, 0x3b, 0xfa, 0xd5, 0x37, 0x5f, 0xfb, 0xc9,
+ 0xff, 0x46, 0xd2, 0x19, 0xc7, 0x22, 0x3e, 0x95,
+ 0x45, 0x9d, 0x82, 0xe1, 0xe7, 0x22, 0x9f, 0x63,
+ 0x31, 0x69, 0xd2, 0x6b, 0x57, 0x47, 0x4f, 0xa3,
+ 0x37, 0xc9, 0x98, 0x1c, 0x0b, 0xfb, 0x91, 0x31,
+ 0x4d, 0x55, 0xb9, 0xe9, 0x1c, 0x5a, 0x5e, 0xe4,
+ 0x93, 0x92, 0xcf, 0xc5, 0x23, 0x12, 0xd5, 0x56,
+ 0x2c, 0x4a, 0x6e, 0xff, 0xdc, 0x10, 0xd0, 0x68 };
+
+static const unsigned char entropy_source_nopr[64] =
+ { 0x5a, 0x19, 0x4d, 0x5e, 0x2b, 0x31, 0x58, 0x14,
+ 0x54, 0xde, 0xf6, 0x75, 0xfb, 0x79, 0x58, 0xfe,
+ 0xc7, 0xdb, 0x87, 0x3e, 0x56, 0x89, 0xfc, 0x9d,
+ 0x03, 0x21, 0x7c, 0x68, 0xd8, 0x03, 0x38, 0x20,
+ 0xf9, 0xe6, 0x5e, 0x04, 0xd8, 0x56, 0xf3, 0xa9,
+ 0xc4, 0x4a, 0x4c, 0xbd, 0xc1, 0xd0, 0x08, 0x46,
+ 0xf5, 0x98, 0x3d, 0x77, 0x1c, 0x1b, 0x13, 0x7e,
+ 0x4e, 0x0f, 0x9d, 0x8e, 0xf4, 0x09, 0xf9, 0x2e };
+
+static const unsigned char nonce_pers_pr[16] =
+ { 0xd2, 0x54, 0xfc, 0xff, 0x02, 0x1e, 0x69, 0xd2,
+ 0x29, 0xc9, 0xcf, 0xad, 0x85, 0xfa, 0x48, 0x6c };
+
+static const unsigned char nonce_pers_nopr[16] =
+ { 0x1b, 0x54, 0xb8, 0xff, 0x06, 0x42, 0xbf, 0xf5,
+ 0x21, 0xf1, 0x5c, 0x1c, 0x0b, 0x66, 0x5f, 0x3f };
+
+static const unsigned char result_pr[16] =
+ { 0x34, 0x01, 0x16, 0x56, 0xb4, 0x29, 0x00, 0x8f,
+ 0x35, 0x63, 0xec, 0xb5, 0xf2, 0x59, 0x07, 0x23 };
+
+static const unsigned char result_nopr[16] =
+ { 0xa0, 0x54, 0x30, 0x3d, 0x8a, 0x7e, 0xa9, 0x88,
+ 0x9d, 0x90, 0x3e, 0x07, 0x7c, 0x6f, 0x21, 0x8f };
+
+static size_t test_offset;
+static int ctr_drbg_self_test_entropy( void *data, unsigned char *buf,
+ size_t len )
+{
+ const unsigned char *p = data;
+ memcpy( buf, p + test_offset, len );
+ test_offset += len;
+ return( 0 );
+}
+
+#define CHK( c ) if( (c) != 0 ) \
+ { \
+ if( verbose != 0 ) \
+ mbedcrypto_printf( "failed\n" ); \
+ return( 1 ); \
+ }
+
+/*
+ * Checkup routine
+ */
+int mbedcrypto_ctr_drbg_self_test( int verbose )
+{
+ mbedcrypto_ctr_drbg_context ctx;
+ unsigned char buf[16];
+
+ mbedcrypto_ctr_drbg_init( &ctx );
+
+ /*
+ * Based on a NIST CTR_DRBG test vector (PR = True)
+ */
+ if( verbose != 0 )
+ mbedcrypto_printf( " CTR_DRBG (PR = TRUE) : " );
+
+ test_offset = 0;
+ CHK( mbedcrypto_ctr_drbg_seed_entropy_len( &ctx, ctr_drbg_self_test_entropy,
+ (void *) entropy_source_pr, nonce_pers_pr, 16, 32 ) );
+ mbedcrypto_ctr_drbg_set_prediction_resistance( &ctx, MBEDCRYPTO_CTR_DRBG_PR_ON );
+ CHK( mbedcrypto_ctr_drbg_random( &ctx, buf, MBEDCRYPTO_CTR_DRBG_BLOCKSIZE ) );
+ CHK( mbedcrypto_ctr_drbg_random( &ctx, buf, MBEDCRYPTO_CTR_DRBG_BLOCKSIZE ) );
+ CHK( memcmp( buf, result_pr, MBEDCRYPTO_CTR_DRBG_BLOCKSIZE ) );
+
+ mbedcrypto_ctr_drbg_free( &ctx );
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+
+ /*
+ * Based on a NIST CTR_DRBG test vector (PR = FALSE)
+ */
+ if( verbose != 0 )
+ mbedcrypto_printf( " CTR_DRBG (PR = FALSE): " );
+
+ mbedcrypto_ctr_drbg_init( &ctx );
+
+ test_offset = 0;
+ CHK( mbedcrypto_ctr_drbg_seed_entropy_len( &ctx, ctr_drbg_self_test_entropy,
+ (void *) entropy_source_nopr, nonce_pers_nopr, 16, 32 ) );
+ CHK( mbedcrypto_ctr_drbg_random( &ctx, buf, 16 ) );
+ CHK( mbedcrypto_ctr_drbg_reseed( &ctx, NULL, 0 ) );
+ CHK( mbedcrypto_ctr_drbg_random( &ctx, buf, 16 ) );
+ CHK( memcmp( buf, result_nopr, 16 ) );
+
+ mbedcrypto_ctr_drbg_free( &ctx );
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "\n" );
+
+ return( 0 );
+}
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#endif /* MBEDCRYPTO_CTR_DRBG_C */
diff --git a/library/des.c b/library/des.c
new file mode 100644
index 0000000..b967dab
--- /dev/null
+++ b/library/des.c
@@ -0,0 +1,1057 @@
+/*
+ * FIPS-46-3 compliant Triple-DES 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 Crypto (https://tls.mbed.org)
+ */
+/*
+ * DES, on which TDES is based, was originally designed by Horst Feistel
+ * at IBM in 1974, and was adopted as a standard by NIST (formerly NBS).
+ *
+ * http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_DES_C)
+
+#include "mbedcrypto/des.h"
+#include "mbedcrypto/platform_util.h"
+
+#include <string.h>
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#include <stdio.h>
+#define mbedcrypto_printf printf
+#endif /* MBEDCRYPTO_PLATFORM_C */
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#if !defined(MBEDCRYPTO_DES_ALT)
+
+/*
+ * 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
+
+/*
+ * Expanded DES S-boxes
+ */
+static const uint32_t SB1[64] =
+{
+ 0x01010400, 0x00000000, 0x00010000, 0x01010404,
+ 0x01010004, 0x00010404, 0x00000004, 0x00010000,
+ 0x00000400, 0x01010400, 0x01010404, 0x00000400,
+ 0x01000404, 0x01010004, 0x01000000, 0x00000004,
+ 0x00000404, 0x01000400, 0x01000400, 0x00010400,
+ 0x00010400, 0x01010000, 0x01010000, 0x01000404,
+ 0x00010004, 0x01000004, 0x01000004, 0x00010004,
+ 0x00000000, 0x00000404, 0x00010404, 0x01000000,
+ 0x00010000, 0x01010404, 0x00000004, 0x01010000,
+ 0x01010400, 0x01000000, 0x01000000, 0x00000400,
+ 0x01010004, 0x00010000, 0x00010400, 0x01000004,
+ 0x00000400, 0x00000004, 0x01000404, 0x00010404,
+ 0x01010404, 0x00010004, 0x01010000, 0x01000404,
+ 0x01000004, 0x00000404, 0x00010404, 0x01010400,
+ 0x00000404, 0x01000400, 0x01000400, 0x00000000,
+ 0x00010004, 0x00010400, 0x00000000, 0x01010004
+};
+
+static const uint32_t SB2[64] =
+{
+ 0x80108020, 0x80008000, 0x00008000, 0x00108020,
+ 0x00100000, 0x00000020, 0x80100020, 0x80008020,
+ 0x80000020, 0x80108020, 0x80108000, 0x80000000,
+ 0x80008000, 0x00100000, 0x00000020, 0x80100020,
+ 0x00108000, 0x00100020, 0x80008020, 0x00000000,
+ 0x80000000, 0x00008000, 0x00108020, 0x80100000,
+ 0x00100020, 0x80000020, 0x00000000, 0x00108000,
+ 0x00008020, 0x80108000, 0x80100000, 0x00008020,
+ 0x00000000, 0x00108020, 0x80100020, 0x00100000,
+ 0x80008020, 0x80100000, 0x80108000, 0x00008000,
+ 0x80100000, 0x80008000, 0x00000020, 0x80108020,
+ 0x00108020, 0x00000020, 0x00008000, 0x80000000,
+ 0x00008020, 0x80108000, 0x00100000, 0x80000020,
+ 0x00100020, 0x80008020, 0x80000020, 0x00100020,
+ 0x00108000, 0x00000000, 0x80008000, 0x00008020,
+ 0x80000000, 0x80100020, 0x80108020, 0x00108000
+};
+
+static const uint32_t SB3[64] =
+{
+ 0x00000208, 0x08020200, 0x00000000, 0x08020008,
+ 0x08000200, 0x00000000, 0x00020208, 0x08000200,
+ 0x00020008, 0x08000008, 0x08000008, 0x00020000,
+ 0x08020208, 0x00020008, 0x08020000, 0x00000208,
+ 0x08000000, 0x00000008, 0x08020200, 0x00000200,
+ 0x00020200, 0x08020000, 0x08020008, 0x00020208,
+ 0x08000208, 0x00020200, 0x00020000, 0x08000208,
+ 0x00000008, 0x08020208, 0x00000200, 0x08000000,
+ 0x08020200, 0x08000000, 0x00020008, 0x00000208,
+ 0x00020000, 0x08020200, 0x08000200, 0x00000000,
+ 0x00000200, 0x00020008, 0x08020208, 0x08000200,
+ 0x08000008, 0x00000200, 0x00000000, 0x08020008,
+ 0x08000208, 0x00020000, 0x08000000, 0x08020208,
+ 0x00000008, 0x00020208, 0x00020200, 0x08000008,
+ 0x08020000, 0x08000208, 0x00000208, 0x08020000,
+ 0x00020208, 0x00000008, 0x08020008, 0x00020200
+};
+
+static const uint32_t SB4[64] =
+{
+ 0x00802001, 0x00002081, 0x00002081, 0x00000080,
+ 0x00802080, 0x00800081, 0x00800001, 0x00002001,
+ 0x00000000, 0x00802000, 0x00802000, 0x00802081,
+ 0x00000081, 0x00000000, 0x00800080, 0x00800001,
+ 0x00000001, 0x00002000, 0x00800000, 0x00802001,
+ 0x00000080, 0x00800000, 0x00002001, 0x00002080,
+ 0x00800081, 0x00000001, 0x00002080, 0x00800080,
+ 0x00002000, 0x00802080, 0x00802081, 0x00000081,
+ 0x00800080, 0x00800001, 0x00802000, 0x00802081,
+ 0x00000081, 0x00000000, 0x00000000, 0x00802000,
+ 0x00002080, 0x00800080, 0x00800081, 0x00000001,
+ 0x00802001, 0x00002081, 0x00002081, 0x00000080,
+ 0x00802081, 0x00000081, 0x00000001, 0x00002000,
+ 0x00800001, 0x00002001, 0x00802080, 0x00800081,
+ 0x00002001, 0x00002080, 0x00800000, 0x00802001,
+ 0x00000080, 0x00800000, 0x00002000, 0x00802080
+};
+
+static const uint32_t SB5[64] =
+{
+ 0x00000100, 0x02080100, 0x02080000, 0x42000100,
+ 0x00080000, 0x00000100, 0x40000000, 0x02080000,
+ 0x40080100, 0x00080000, 0x02000100, 0x40080100,
+ 0x42000100, 0x42080000, 0x00080100, 0x40000000,
+ 0x02000000, 0x40080000, 0x40080000, 0x00000000,
+ 0x40000100, 0x42080100, 0x42080100, 0x02000100,
+ 0x42080000, 0x40000100, 0x00000000, 0x42000000,
+ 0x02080100, 0x02000000, 0x42000000, 0x00080100,
+ 0x00080000, 0x42000100, 0x00000100, 0x02000000,
+ 0x40000000, 0x02080000, 0x42000100, 0x40080100,
+ 0x02000100, 0x40000000, 0x42080000, 0x02080100,
+ 0x40080100, 0x00000100, 0x02000000, 0x42080000,
+ 0x42080100, 0x00080100, 0x42000000, 0x42080100,
+ 0x02080000, 0x00000000, 0x40080000, 0x42000000,
+ 0x00080100, 0x02000100, 0x40000100, 0x00080000,
+ 0x00000000, 0x40080000, 0x02080100, 0x40000100
+};
+
+static const uint32_t SB6[64] =
+{
+ 0x20000010, 0x20400000, 0x00004000, 0x20404010,
+ 0x20400000, 0x00000010, 0x20404010, 0x00400000,
+ 0x20004000, 0x00404010, 0x00400000, 0x20000010,
+ 0x00400010, 0x20004000, 0x20000000, 0x00004010,
+ 0x00000000, 0x00400010, 0x20004010, 0x00004000,
+ 0x00404000, 0x20004010, 0x00000010, 0x20400010,
+ 0x20400010, 0x00000000, 0x00404010, 0x20404000,
+ 0x00004010, 0x00404000, 0x20404000, 0x20000000,
+ 0x20004000, 0x00000010, 0x20400010, 0x00404000,
+ 0x20404010, 0x00400000, 0x00004010, 0x20000010,
+ 0x00400000, 0x20004000, 0x20000000, 0x00004010,
+ 0x20000010, 0x20404010, 0x00404000, 0x20400000,
+ 0x00404010, 0x20404000, 0x00000000, 0x20400010,
+ 0x00000010, 0x00004000, 0x20400000, 0x00404010,
+ 0x00004000, 0x00400010, 0x20004010, 0x00000000,
+ 0x20404000, 0x20000000, 0x00400010, 0x20004010
+};
+
+static const uint32_t SB7[64] =
+{
+ 0x00200000, 0x04200002, 0x04000802, 0x00000000,
+ 0x00000800, 0x04000802, 0x00200802, 0x04200800,
+ 0x04200802, 0x00200000, 0x00000000, 0x04000002,
+ 0x00000002, 0x04000000, 0x04200002, 0x00000802,
+ 0x04000800, 0x00200802, 0x00200002, 0x04000800,
+ 0x04000002, 0x04200000, 0x04200800, 0x00200002,
+ 0x04200000, 0x00000800, 0x00000802, 0x04200802,
+ 0x00200800, 0x00000002, 0x04000000, 0x00200800,
+ 0x04000000, 0x00200800, 0x00200000, 0x04000802,
+ 0x04000802, 0x04200002, 0x04200002, 0x00000002,
+ 0x00200002, 0x04000000, 0x04000800, 0x00200000,
+ 0x04200800, 0x00000802, 0x00200802, 0x04200800,
+ 0x00000802, 0x04000002, 0x04200802, 0x04200000,
+ 0x00200800, 0x00000000, 0x00000002, 0x04200802,
+ 0x00000000, 0x00200802, 0x04200000, 0x00000800,
+ 0x04000002, 0x04000800, 0x00000800, 0x00200002
+};
+
+static const uint32_t SB8[64] =
+{
+ 0x10001040, 0x00001000, 0x00040000, 0x10041040,
+ 0x10000000, 0x10001040, 0x00000040, 0x10000000,
+ 0x00040040, 0x10040000, 0x10041040, 0x00041000,
+ 0x10041000, 0x00041040, 0x00001000, 0x00000040,
+ 0x10040000, 0x10000040, 0x10001000, 0x00001040,
+ 0x00041000, 0x00040040, 0x10040040, 0x10041000,
+ 0x00001040, 0x00000000, 0x00000000, 0x10040040,
+ 0x10000040, 0x10001000, 0x00041040, 0x00040000,
+ 0x00041040, 0x00040000, 0x10041000, 0x00001000,
+ 0x00000040, 0x10040040, 0x00001000, 0x00041040,
+ 0x10001000, 0x00000040, 0x10000040, 0x10040000,
+ 0x10040040, 0x10000000, 0x00040000, 0x10001040,
+ 0x00000000, 0x10041040, 0x00040040, 0x10000040,
+ 0x10040000, 0x10001000, 0x10001040, 0x00000000,
+ 0x10041040, 0x00041000, 0x00041000, 0x00001040,
+ 0x00001040, 0x00040040, 0x10000000, 0x10041000
+};
+
+/*
+ * PC1: left and right halves bit-swap
+ */
+static const uint32_t LHs[16] =
+{
+ 0x00000000, 0x00000001, 0x00000100, 0x00000101,
+ 0x00010000, 0x00010001, 0x00010100, 0x00010101,
+ 0x01000000, 0x01000001, 0x01000100, 0x01000101,
+ 0x01010000, 0x01010001, 0x01010100, 0x01010101
+};
+
+static const uint32_t RHs[16] =
+{
+ 0x00000000, 0x01000000, 0x00010000, 0x01010000,
+ 0x00000100, 0x01000100, 0x00010100, 0x01010100,
+ 0x00000001, 0x01000001, 0x00010001, 0x01010001,
+ 0x00000101, 0x01000101, 0x00010101, 0x01010101,
+};
+
+/*
+ * Initial Permutation macro
+ */
+#define DES_IP(X,Y) \
+{ \
+ T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \
+ T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \
+ T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \
+ T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \
+ Y = ((Y << 1) | (Y >> 31)) & 0xFFFFFFFF; \
+ T = (X ^ Y) & 0xAAAAAAAA; Y ^= T; X ^= T; \
+ X = ((X << 1) | (X >> 31)) & 0xFFFFFFFF; \
+}
+
+/*
+ * Final Permutation macro
+ */
+#define DES_FP(X,Y) \
+{ \
+ X = ((X << 31) | (X >> 1)) & 0xFFFFFFFF; \
+ T = (X ^ Y) & 0xAAAAAAAA; X ^= T; Y ^= T; \
+ Y = ((Y << 31) | (Y >> 1)) & 0xFFFFFFFF; \
+ T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \
+ T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \
+ T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \
+ T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \
+}
+
+/*
+ * DES round macro
+ */
+#define DES_ROUND(X,Y) \
+{ \
+ T = *SK++ ^ X; \
+ Y ^= SB8[ (T ) & 0x3F ] ^ \
+ SB6[ (T >> 8) & 0x3F ] ^ \
+ SB4[ (T >> 16) & 0x3F ] ^ \
+ SB2[ (T >> 24) & 0x3F ]; \
+ \
+ T = *SK++ ^ ((X << 28) | (X >> 4)); \
+ Y ^= SB7[ (T ) & 0x3F ] ^ \
+ SB5[ (T >> 8) & 0x3F ] ^ \
+ SB3[ (T >> 16) & 0x3F ] ^ \
+ SB1[ (T >> 24) & 0x3F ]; \
+}
+
+#define SWAP(a,b) { uint32_t t = a; a = b; b = t; t = 0; }
+
+void mbedcrypto_des_init( mbedcrypto_des_context *ctx )
+{
+ memset( ctx, 0, sizeof( mbedcrypto_des_context ) );
+}
+
+void mbedcrypto_des_free( mbedcrypto_des_context *ctx )
+{
+ if( ctx == NULL )
+ return;
+
+ mbedcrypto_platform_zeroize( ctx, sizeof( mbedcrypto_des_context ) );
+}
+
+void mbedcrypto_des3_init( mbedcrypto_des3_context *ctx )
+{
+ memset( ctx, 0, sizeof( mbedcrypto_des3_context ) );
+}
+
+void mbedcrypto_des3_free( mbedcrypto_des3_context *ctx )
+{
+ if( ctx == NULL )
+ return;
+
+ mbedcrypto_platform_zeroize( ctx, sizeof( mbedcrypto_des3_context ) );
+}
+
+static const unsigned char odd_parity_table[128] = { 1, 2, 4, 7, 8,
+ 11, 13, 14, 16, 19, 21, 22, 25, 26, 28, 31, 32, 35, 37, 38, 41, 42, 44,
+ 47, 49, 50, 52, 55, 56, 59, 61, 62, 64, 67, 69, 70, 73, 74, 76, 79, 81,
+ 82, 84, 87, 88, 91, 93, 94, 97, 98, 100, 103, 104, 107, 109, 110, 112,
+ 115, 117, 118, 121, 122, 124, 127, 128, 131, 133, 134, 137, 138, 140,
+ 143, 145, 146, 148, 151, 152, 155, 157, 158, 161, 162, 164, 167, 168,
+ 171, 173, 174, 176, 179, 181, 182, 185, 186, 188, 191, 193, 194, 196,
+ 199, 200, 203, 205, 206, 208, 211, 213, 214, 217, 218, 220, 223, 224,
+ 227, 229, 230, 233, 234, 236, 239, 241, 242, 244, 247, 248, 251, 253,
+ 254 };
+
+void mbedcrypto_des_key_set_parity( unsigned char key[MBEDCRYPTO_DES_KEY_SIZE] )
+{
+ int i;
+
+ for( i = 0; i < MBEDCRYPTO_DES_KEY_SIZE; i++ )
+ key[i] = odd_parity_table[key[i] / 2];
+}
+
+/*
+ * Check the given key's parity, returns 1 on failure, 0 on SUCCESS
+ */
+int mbedcrypto_des_key_check_key_parity( const unsigned char key[MBEDCRYPTO_DES_KEY_SIZE] )
+{
+ int i;
+
+ for( i = 0; i < MBEDCRYPTO_DES_KEY_SIZE; i++ )
+ if( key[i] != odd_parity_table[key[i] / 2] )
+ return( 1 );
+
+ return( 0 );
+}
+
+/*
+ * Table of weak and semi-weak keys
+ *
+ * Source: http://en.wikipedia.org/wiki/Weak_key
+ *
+ * Weak:
+ * Alternating ones + zeros (0x0101010101010101)
+ * Alternating 'F' + 'E' (0xFEFEFEFEFEFEFEFE)
+ * '0xE0E0E0E0F1F1F1F1'
+ * '0x1F1F1F1F0E0E0E0E'
+ *
+ * Semi-weak:
+ * 0x011F011F010E010E and 0x1F011F010E010E01
+ * 0x01E001E001F101F1 and 0xE001E001F101F101
+ * 0x01FE01FE01FE01FE and 0xFE01FE01FE01FE01
+ * 0x1FE01FE00EF10EF1 and 0xE01FE01FF10EF10E
+ * 0x1FFE1FFE0EFE0EFE and 0xFE1FFE1FFE0EFE0E
+ * 0xE0FEE0FEF1FEF1FE and 0xFEE0FEE0FEF1FEF1
+ *
+ */
+
+#define WEAK_KEY_COUNT 16
+
+static const unsigned char weak_key_table[WEAK_KEY_COUNT][MBEDCRYPTO_DES_KEY_SIZE] =
+{
+ { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+ { 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE },
+ { 0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E },
+ { 0xE0, 0xE0, 0xE0, 0xE0, 0xF1, 0xF1, 0xF1, 0xF1 },
+
+ { 0x01, 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E },
+ { 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E, 0x01 },
+ { 0x01, 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1 },
+ { 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1, 0x01 },
+ { 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE },
+ { 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01 },
+ { 0x1F, 0xE0, 0x1F, 0xE0, 0x0E, 0xF1, 0x0E, 0xF1 },
+ { 0xE0, 0x1F, 0xE0, 0x1F, 0xF1, 0x0E, 0xF1, 0x0E },
+ { 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E, 0xFE },
+ { 0xFE, 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E },
+ { 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1, 0xFE },
+ { 0xFE, 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1 }
+};
+
+int mbedcrypto_des_key_check_weak( const unsigned char key[MBEDCRYPTO_DES_KEY_SIZE] )
+{
+ int i;
+
+ for( i = 0; i < WEAK_KEY_COUNT; i++ )
+ if( memcmp( weak_key_table[i], key, MBEDCRYPTO_DES_KEY_SIZE) == 0 )
+ return( 1 );
+
+ return( 0 );
+}
+
+#if !defined(MBEDCRYPTO_DES_SETKEY_ALT)
+void mbedcrypto_des_setkey( uint32_t SK[32], const unsigned char key[MBEDCRYPTO_DES_KEY_SIZE] )
+{
+ int i;
+ uint32_t X, Y, T;
+
+ GET_UINT32_BE( X, key, 0 );
+ GET_UINT32_BE( Y, key, 4 );
+
+ /*
+ * Permuted Choice 1
+ */
+ T = ((Y >> 4) ^ X) & 0x0F0F0F0F; X ^= T; Y ^= (T << 4);
+ T = ((Y ) ^ X) & 0x10101010; X ^= T; Y ^= (T );
+
+ X = (LHs[ (X ) & 0xF] << 3) | (LHs[ (X >> 8) & 0xF ] << 2)
+ | (LHs[ (X >> 16) & 0xF] << 1) | (LHs[ (X >> 24) & 0xF ] )
+ | (LHs[ (X >> 5) & 0xF] << 7) | (LHs[ (X >> 13) & 0xF ] << 6)
+ | (LHs[ (X >> 21) & 0xF] << 5) | (LHs[ (X >> 29) & 0xF ] << 4);
+
+ Y = (RHs[ (Y >> 1) & 0xF] << 3) | (RHs[ (Y >> 9) & 0xF ] << 2)
+ | (RHs[ (Y >> 17) & 0xF] << 1) | (RHs[ (Y >> 25) & 0xF ] )
+ | (RHs[ (Y >> 4) & 0xF] << 7) | (RHs[ (Y >> 12) & 0xF ] << 6)
+ | (RHs[ (Y >> 20) & 0xF] << 5) | (RHs[ (Y >> 28) & 0xF ] << 4);
+
+ X &= 0x0FFFFFFF;
+ Y &= 0x0FFFFFFF;
+
+ /*
+ * calculate subkeys
+ */
+ for( i = 0; i < 16; i++ )
+ {
+ if( i < 2 || i == 8 || i == 15 )
+ {
+ X = ((X << 1) | (X >> 27)) & 0x0FFFFFFF;
+ Y = ((Y << 1) | (Y >> 27)) & 0x0FFFFFFF;
+ }
+ else
+ {
+ X = ((X << 2) | (X >> 26)) & 0x0FFFFFFF;
+ Y = ((Y << 2) | (Y >> 26)) & 0x0FFFFFFF;
+ }
+
+ *SK++ = ((X << 4) & 0x24000000) | ((X << 28) & 0x10000000)
+ | ((X << 14) & 0x08000000) | ((X << 18) & 0x02080000)
+ | ((X << 6) & 0x01000000) | ((X << 9) & 0x00200000)
+ | ((X >> 1) & 0x00100000) | ((X << 10) & 0x00040000)
+ | ((X << 2) & 0x00020000) | ((X >> 10) & 0x00010000)
+ | ((Y >> 13) & 0x00002000) | ((Y >> 4) & 0x00001000)
+ | ((Y << 6) & 0x00000800) | ((Y >> 1) & 0x00000400)
+ | ((Y >> 14) & 0x00000200) | ((Y ) & 0x00000100)
+ | ((Y >> 5) & 0x00000020) | ((Y >> 10) & 0x00000010)
+ | ((Y >> 3) & 0x00000008) | ((Y >> 18) & 0x00000004)
+ | ((Y >> 26) & 0x00000002) | ((Y >> 24) & 0x00000001);
+
+ *SK++ = ((X << 15) & 0x20000000) | ((X << 17) & 0x10000000)
+ | ((X << 10) & 0x08000000) | ((X << 22) & 0x04000000)
+ | ((X >> 2) & 0x02000000) | ((X << 1) & 0x01000000)
+ | ((X << 16) & 0x00200000) | ((X << 11) & 0x00100000)
+ | ((X << 3) & 0x00080000) | ((X >> 6) & 0x00040000)
+ | ((X << 15) & 0x00020000) | ((X >> 4) & 0x00010000)
+ | ((Y >> 2) & 0x00002000) | ((Y << 8) & 0x00001000)
+ | ((Y >> 14) & 0x00000808) | ((Y >> 9) & 0x00000400)
+ | ((Y ) & 0x00000200) | ((Y << 7) & 0x00000100)
+ | ((Y >> 7) & 0x00000020) | ((Y >> 3) & 0x00000011)
+ | ((Y << 2) & 0x00000004) | ((Y >> 21) & 0x00000002);
+ }
+}
+#endif /* !MBEDCRYPTO_DES_SETKEY_ALT */
+
+/*
+ * DES key schedule (56-bit, encryption)
+ */
+int mbedcrypto_des_setkey_enc( mbedcrypto_des_context *ctx, const unsigned char key[MBEDCRYPTO_DES_KEY_SIZE] )
+{
+ mbedcrypto_des_setkey( ctx->sk, key );
+
+ return( 0 );
+}
+
+/*
+ * DES key schedule (56-bit, decryption)
+ */
+int mbedcrypto_des_setkey_dec( mbedcrypto_des_context *ctx, const unsigned char key[MBEDCRYPTO_DES_KEY_SIZE] )
+{
+ int i;
+
+ mbedcrypto_des_setkey( ctx->sk, key );
+
+ for( i = 0; i < 16; i += 2 )
+ {
+ SWAP( ctx->sk[i ], ctx->sk[30 - i] );
+ SWAP( ctx->sk[i + 1], ctx->sk[31 - i] );
+ }
+
+ return( 0 );
+}
+
+static void des3_set2key( uint32_t esk[96],
+ uint32_t dsk[96],
+ const unsigned char key[MBEDCRYPTO_DES_KEY_SIZE*2] )
+{
+ int i;
+
+ mbedcrypto_des_setkey( esk, key );
+ mbedcrypto_des_setkey( dsk + 32, key + 8 );
+
+ for( i = 0; i < 32; i += 2 )
+ {
+ dsk[i ] = esk[30 - i];
+ dsk[i + 1] = esk[31 - i];
+
+ esk[i + 32] = dsk[62 - i];
+ esk[i + 33] = dsk[63 - i];
+
+ esk[i + 64] = esk[i ];
+ esk[i + 65] = esk[i + 1];
+
+ dsk[i + 64] = dsk[i ];
+ dsk[i + 65] = dsk[i + 1];
+ }
+}
+
+/*
+ * Triple-DES key schedule (112-bit, encryption)
+ */
+int mbedcrypto_des3_set2key_enc( mbedcrypto_des3_context *ctx,
+ const unsigned char key[MBEDCRYPTO_DES_KEY_SIZE * 2] )
+{
+ uint32_t sk[96];
+
+ des3_set2key( ctx->sk, sk, key );
+ mbedcrypto_platform_zeroize( sk, sizeof( sk ) );
+
+ return( 0 );
+}
+
+/*
+ * Triple-DES key schedule (112-bit, decryption)
+ */
+int mbedcrypto_des3_set2key_dec( mbedcrypto_des3_context *ctx,
+ const unsigned char key[MBEDCRYPTO_DES_KEY_SIZE * 2] )
+{
+ uint32_t sk[96];
+
+ des3_set2key( sk, ctx->sk, key );
+ mbedcrypto_platform_zeroize( sk, sizeof( sk ) );
+
+ return( 0 );
+}
+
+static void des3_set3key( uint32_t esk[96],
+ uint32_t dsk[96],
+ const unsigned char key[24] )
+{
+ int i;
+
+ mbedcrypto_des_setkey( esk, key );
+ mbedcrypto_des_setkey( dsk + 32, key + 8 );
+ mbedcrypto_des_setkey( esk + 64, key + 16 );
+
+ for( i = 0; i < 32; i += 2 )
+ {
+ dsk[i ] = esk[94 - i];
+ dsk[i + 1] = esk[95 - i];
+
+ esk[i + 32] = dsk[62 - i];
+ esk[i + 33] = dsk[63 - i];
+
+ dsk[i + 64] = esk[30 - i];
+ dsk[i + 65] = esk[31 - i];
+ }
+}
+
+/*
+ * Triple-DES key schedule (168-bit, encryption)
+ */
+int mbedcrypto_des3_set3key_enc( mbedcrypto_des3_context *ctx,
+ const unsigned char key[MBEDCRYPTO_DES_KEY_SIZE * 3] )
+{
+ uint32_t sk[96];
+
+ des3_set3key( ctx->sk, sk, key );
+ mbedcrypto_platform_zeroize( sk, sizeof( sk ) );
+
+ return( 0 );
+}
+
+/*
+ * Triple-DES key schedule (168-bit, decryption)
+ */
+int mbedcrypto_des3_set3key_dec( mbedcrypto_des3_context *ctx,
+ const unsigned char key[MBEDCRYPTO_DES_KEY_SIZE * 3] )
+{
+ uint32_t sk[96];
+
+ des3_set3key( sk, ctx->sk, key );
+ mbedcrypto_platform_zeroize( sk, sizeof( sk ) );
+
+ return( 0 );
+}
+
+/*
+ * DES-ECB block encryption/decryption
+ */
+#if !defined(MBEDCRYPTO_DES_CRYPT_ECB_ALT)
+int mbedcrypto_des_crypt_ecb( mbedcrypto_des_context *ctx,
+ const unsigned char input[8],
+ unsigned char output[8] )
+{
+ int i;
+ uint32_t X, Y, T, *SK;
+
+ SK = ctx->sk;
+
+ GET_UINT32_BE( X, input, 0 );
+ GET_UINT32_BE( Y, input, 4 );
+
+ DES_IP( X, Y );
+
+ for( i = 0; i < 8; i++ )
+ {
+ DES_ROUND( Y, X );
+ DES_ROUND( X, Y );
+ }
+
+ DES_FP( Y, X );
+
+ PUT_UINT32_BE( Y, output, 0 );
+ PUT_UINT32_BE( X, output, 4 );
+
+ return( 0 );
+}
+#endif /* !MBEDCRYPTO_DES_CRYPT_ECB_ALT */
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+/*
+ * DES-CBC buffer encryption/decryption
+ */
+int mbedcrypto_des_crypt_cbc( mbedcrypto_des_context *ctx,
+ int mode,
+ size_t length,
+ unsigned char iv[8],
+ const unsigned char *input,
+ unsigned char *output )
+{
+ int i;
+ unsigned char temp[8];
+
+ if( length % 8 )
+ return( MBEDCRYPTO_ERR_DES_INVALID_INPUT_LENGTH );
+
+ if( mode == MBEDCRYPTO_DES_ENCRYPT )
+ {
+ while( length > 0 )
+ {
+ for( i = 0; i < 8; i++ )
+ output[i] = (unsigned char)( input[i] ^ iv[i] );
+
+ mbedcrypto_des_crypt_ecb( ctx, output, output );
+ memcpy( iv, output, 8 );
+
+ input += 8;
+ output += 8;
+ length -= 8;
+ }
+ }
+ else /* MBEDCRYPTO_DES_DECRYPT */
+ {
+ while( length > 0 )
+ {
+ memcpy( temp, input, 8 );
+ mbedcrypto_des_crypt_ecb( ctx, input, output );
+
+ for( i = 0; i < 8; i++ )
+ output[i] = (unsigned char)( output[i] ^ iv[i] );
+
+ memcpy( iv, temp, 8 );
+
+ input += 8;
+ output += 8;
+ length -= 8;
+ }
+ }
+
+ return( 0 );
+}
+#endif /* MBEDCRYPTO_CIPHER_MODE_CBC */
+
+/*
+ * 3DES-ECB block encryption/decryption
+ */
+#if !defined(MBEDCRYPTO_DES3_CRYPT_ECB_ALT)
+int mbedcrypto_des3_crypt_ecb( mbedcrypto_des3_context *ctx,
+ const unsigned char input[8],
+ unsigned char output[8] )
+{
+ int i;
+ uint32_t X, Y, T, *SK;
+
+ SK = ctx->sk;
+
+ GET_UINT32_BE( X, input, 0 );
+ GET_UINT32_BE( Y, input, 4 );
+
+ DES_IP( X, Y );
+
+ for( i = 0; i < 8; i++ )
+ {
+ DES_ROUND( Y, X );
+ DES_ROUND( X, Y );
+ }
+
+ for( i = 0; i < 8; i++ )
+ {
+ DES_ROUND( X, Y );
+ DES_ROUND( Y, X );
+ }
+
+ for( i = 0; i < 8; i++ )
+ {
+ DES_ROUND( Y, X );
+ DES_ROUND( X, Y );
+ }
+
+ DES_FP( Y, X );
+
+ PUT_UINT32_BE( Y, output, 0 );
+ PUT_UINT32_BE( X, output, 4 );
+
+ return( 0 );
+}
+#endif /* !MBEDCRYPTO_DES3_CRYPT_ECB_ALT */
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+/*
+ * 3DES-CBC buffer encryption/decryption
+ */
+int mbedcrypto_des3_crypt_cbc( mbedcrypto_des3_context *ctx,
+ int mode,
+ size_t length,
+ unsigned char iv[8],
+ const unsigned char *input,
+ unsigned char *output )
+{
+ int i;
+ unsigned char temp[8];
+
+ if( length % 8 )
+ return( MBEDCRYPTO_ERR_DES_INVALID_INPUT_LENGTH );
+
+ if( mode == MBEDCRYPTO_DES_ENCRYPT )
+ {
+ while( length > 0 )
+ {
+ for( i = 0; i < 8; i++ )
+ output[i] = (unsigned char)( input[i] ^ iv[i] );
+
+ mbedcrypto_des3_crypt_ecb( ctx, output, output );
+ memcpy( iv, output, 8 );
+
+ input += 8;
+ output += 8;
+ length -= 8;
+ }
+ }
+ else /* MBEDCRYPTO_DES_DECRYPT */
+ {
+ while( length > 0 )
+ {
+ memcpy( temp, input, 8 );
+ mbedcrypto_des3_crypt_ecb( ctx, input, output );
+
+ for( i = 0; i < 8; i++ )
+ output[i] = (unsigned char)( output[i] ^ iv[i] );
+
+ memcpy( iv, temp, 8 );
+
+ input += 8;
+ output += 8;
+ length -= 8;
+ }
+ }
+
+ return( 0 );
+}
+#endif /* MBEDCRYPTO_CIPHER_MODE_CBC */
+
+#endif /* !MBEDCRYPTO_DES_ALT */
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+/*
+ * DES and 3DES test vectors from:
+ *
+ * http://csrc.nist.gov/groups/STM/cavp/documents/des/tripledes-vectors.zip
+ */
+static const unsigned char des3_test_keys[24] =
+{
+ 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
+ 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01,
+ 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23
+};
+
+static const unsigned char des3_test_buf[8] =
+{
+ 0x4E, 0x6F, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74
+};
+
+static const unsigned char des3_test_ecb_dec[3][8] =
+{
+ { 0xCD, 0xD6, 0x4F, 0x2F, 0x94, 0x27, 0xC1, 0x5D },
+ { 0x69, 0x96, 0xC8, 0xFA, 0x47, 0xA2, 0xAB, 0xEB },
+ { 0x83, 0x25, 0x39, 0x76, 0x44, 0x09, 0x1A, 0x0A }
+};
+
+static const unsigned char des3_test_ecb_enc[3][8] =
+{
+ { 0x6A, 0x2A, 0x19, 0xF4, 0x1E, 0xCA, 0x85, 0x4B },
+ { 0x03, 0xE6, 0x9F, 0x5B, 0xFA, 0x58, 0xEB, 0x42 },
+ { 0xDD, 0x17, 0xE8, 0xB8, 0xB4, 0x37, 0xD2, 0x32 }
+};
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+static const unsigned char des3_test_iv[8] =
+{
+ 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF,
+};
+
+static const unsigned char des3_test_cbc_dec[3][8] =
+{
+ { 0x12, 0x9F, 0x40, 0xB9, 0xD2, 0x00, 0x56, 0xB3 },
+ { 0x47, 0x0E, 0xFC, 0x9A, 0x6B, 0x8E, 0xE3, 0x93 },
+ { 0xC5, 0xCE, 0xCF, 0x63, 0xEC, 0xEC, 0x51, 0x4C }
+};
+
+static const unsigned char des3_test_cbc_enc[3][8] =
+{
+ { 0x54, 0xF1, 0x5A, 0xF6, 0xEB, 0xE3, 0xA4, 0xB4 },
+ { 0x35, 0x76, 0x11, 0x56, 0x5F, 0xA1, 0x8E, 0x4D },
+ { 0xCB, 0x19, 0x1F, 0x85, 0xD1, 0xED, 0x84, 0x39 }
+};
+#endif /* MBEDCRYPTO_CIPHER_MODE_CBC */
+
+/*
+ * Checkup routine
+ */
+int mbedcrypto_des_self_test( int verbose )
+{
+ int i, j, u, v, ret = 0;
+ mbedcrypto_des_context ctx;
+ mbedcrypto_des3_context ctx3;
+ unsigned char buf[8];
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+ unsigned char prv[8];
+ unsigned char iv[8];
+#endif
+
+ mbedcrypto_des_init( &ctx );
+ mbedcrypto_des3_init( &ctx3 );
+ /*
+ * ECB mode
+ */
+ for( i = 0; i < 6; i++ )
+ {
+ u = i >> 1;
+ v = i & 1;
+
+ if( verbose != 0 )
+ mbedcrypto_printf( " DES%c-ECB-%3d (%s): ",
+ ( u == 0 ) ? ' ' : '3', 56 + u * 56,
+ ( v == MBEDCRYPTO_DES_DECRYPT ) ? "dec" : "enc" );
+
+ memcpy( buf, des3_test_buf, 8 );
+
+ switch( i )
+ {
+ case 0:
+ mbedcrypto_des_setkey_dec( &ctx, des3_test_keys );
+ break;
+
+ case 1:
+ mbedcrypto_des_setkey_enc( &ctx, des3_test_keys );
+ break;
+
+ case 2:
+ mbedcrypto_des3_set2key_dec( &ctx3, des3_test_keys );
+ break;
+
+ case 3:
+ mbedcrypto_des3_set2key_enc( &ctx3, des3_test_keys );
+ break;
+
+ case 4:
+ mbedcrypto_des3_set3key_dec( &ctx3, des3_test_keys );
+ break;
+
+ case 5:
+ mbedcrypto_des3_set3key_enc( &ctx3, des3_test_keys );
+ break;
+
+ default:
+ return( 1 );
+ }
+
+ for( j = 0; j < 10000; j++ )
+ {
+ if( u == 0 )
+ mbedcrypto_des_crypt_ecb( &ctx, buf, buf );
+ else
+ mbedcrypto_des3_crypt_ecb( &ctx3, buf, buf );
+ }
+
+ if( ( v == MBEDCRYPTO_DES_DECRYPT &&
+ memcmp( buf, des3_test_ecb_dec[u], 8 ) != 0 ) ||
+ ( v != MBEDCRYPTO_DES_DECRYPT &&
+ memcmp( buf, des3_test_ecb_enc[u], 8 ) != 0 ) )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+
+ ret = 1;
+ goto exit;
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "\n" );
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+ /*
+ * CBC mode
+ */
+ for( i = 0; i < 6; i++ )
+ {
+ u = i >> 1;
+ v = i & 1;
+
+ if( verbose != 0 )
+ mbedcrypto_printf( " DES%c-CBC-%3d (%s): ",
+ ( u == 0 ) ? ' ' : '3', 56 + u * 56,
+ ( v == MBEDCRYPTO_DES_DECRYPT ) ? "dec" : "enc" );
+
+ memcpy( iv, des3_test_iv, 8 );
+ memcpy( prv, des3_test_iv, 8 );
+ memcpy( buf, des3_test_buf, 8 );
+
+ switch( i )
+ {
+ case 0:
+ mbedcrypto_des_setkey_dec( &ctx, des3_test_keys );
+ break;
+
+ case 1:
+ mbedcrypto_des_setkey_enc( &ctx, des3_test_keys );
+ break;
+
+ case 2:
+ mbedcrypto_des3_set2key_dec( &ctx3, des3_test_keys );
+ break;
+
+ case 3:
+ mbedcrypto_des3_set2key_enc( &ctx3, des3_test_keys );
+ break;
+
+ case 4:
+ mbedcrypto_des3_set3key_dec( &ctx3, des3_test_keys );
+ break;
+
+ case 5:
+ mbedcrypto_des3_set3key_enc( &ctx3, des3_test_keys );
+ break;
+
+ default:
+ return( 1 );
+ }
+
+ if( v == MBEDCRYPTO_DES_DECRYPT )
+ {
+ for( j = 0; j < 10000; j++ )
+ {
+ if( u == 0 )
+ mbedcrypto_des_crypt_cbc( &ctx, v, 8, iv, buf, buf );
+ else
+ mbedcrypto_des3_crypt_cbc( &ctx3, v, 8, iv, buf, buf );
+ }
+ }
+ else
+ {
+ for( j = 0; j < 10000; j++ )
+ {
+ unsigned char tmp[8];
+
+ if( u == 0 )
+ mbedcrypto_des_crypt_cbc( &ctx, v, 8, iv, buf, buf );
+ else
+ mbedcrypto_des3_crypt_cbc( &ctx3, v, 8, iv, buf, buf );
+
+ memcpy( tmp, prv, 8 );
+ memcpy( prv, buf, 8 );
+ memcpy( buf, tmp, 8 );
+ }
+
+ memcpy( buf, prv, 8 );
+ }
+
+ if( ( v == MBEDCRYPTO_DES_DECRYPT &&
+ memcmp( buf, des3_test_cbc_dec[u], 8 ) != 0 ) ||
+ ( v != MBEDCRYPTO_DES_DECRYPT &&
+ memcmp( buf, des3_test_cbc_enc[u], 8 ) != 0 ) )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+
+ ret = 1;
+ goto exit;
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+ }
+#endif /* MBEDCRYPTO_CIPHER_MODE_CBC */
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "\n" );
+
+exit:
+ mbedcrypto_des_free( &ctx );
+ mbedcrypto_des3_free( &ctx3 );
+
+ return( ret );
+}
+
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#endif /* MBEDCRYPTO_DES_C */
diff --git a/library/ecdsa.c b/library/ecdsa.c
new file mode 100644
index 0000000..a05cae4
--- /dev/null
+++ b/library/ecdsa.c
@@ -0,0 +1,461 @@
+/*
+ * Elliptic curve DSA
+ *
+ * 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 Crypto (https://tls.mbed.org)
+ */
+
+/*
+ * References:
+ *
+ * SEC1 http://www.secg.org/index.php?action=secg,docs_secg
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_ECDSA_C)
+
+#include "mbedcrypto/ecdsa.h"
+#include "mbedcrypto/asn1write.h"
+
+#include <string.h>
+
+#if defined(MBEDCRYPTO_ECDSA_DETERMINISTIC)
+#include "mbedcrypto/hmac_drbg.h"
+#endif
+
+/*
+ * Derive a suitable integer for group grp from a buffer of length len
+ * SEC1 4.1.3 step 5 aka SEC1 4.1.4 step 3
+ */
+static int derive_mpi( const mbedcrypto_ecp_group *grp, mbedcrypto_mpi *x,
+ const unsigned char *buf, size_t blen )
+{
+ int ret;
+ size_t n_size = ( grp->nbits + 7 ) / 8;
+ size_t use_size = blen > n_size ? n_size : blen;
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_binary( x, buf, use_size ) );
+ if( use_size * 8 > grp->nbits )
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_r( x, use_size * 8 - grp->nbits ) );
+
+ /* While at it, reduce modulo N */
+ if( mbedcrypto_mpi_cmp_mpi( x, &grp->N ) >= 0 )
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( x, x, &grp->N ) );
+
+cleanup:
+ return( ret );
+}
+
+#if !defined(MBEDCRYPTO_ECDSA_SIGN_ALT)
+/*
+ * Compute ECDSA signature of a hashed message (SEC1 4.1.3)
+ * Obviously, compared to SEC1 4.1.3, we skip step 4 (hash message)
+ */
+int mbedcrypto_ecdsa_sign( mbedcrypto_ecp_group *grp, mbedcrypto_mpi *r, mbedcrypto_mpi *s,
+ const mbedcrypto_mpi *d, const unsigned char *buf, size_t blen,
+ int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
+{
+ int ret, key_tries, sign_tries, blind_tries;
+ mbedcrypto_ecp_point R;
+ mbedcrypto_mpi k, e, t;
+
+ /* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */
+ if( grp->N.p == NULL )
+ return( MBEDCRYPTO_ERR_ECP_BAD_INPUT_DATA );
+
+ /* Make sure d is in range 1..n-1 */
+ if( mbedcrypto_mpi_cmp_int( d, 1 ) < 0 || mbedcrypto_mpi_cmp_mpi( d, &grp->N ) >= 0 )
+ return( MBEDCRYPTO_ERR_ECP_INVALID_KEY );
+
+ mbedcrypto_ecp_point_init( &R );
+ mbedcrypto_mpi_init( &k ); mbedcrypto_mpi_init( &e ); mbedcrypto_mpi_init( &t );
+
+ sign_tries = 0;
+ do
+ {
+ /*
+ * Steps 1-3: generate a suitable ephemeral keypair
+ * and set r = xR mod n
+ */
+ key_tries = 0;
+ do
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_ecp_gen_keypair( grp, &k, &R, f_rng, p_rng ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mod_mpi( r, &R.X, &grp->N ) );
+
+ if( key_tries++ > 10 )
+ {
+ ret = MBEDCRYPTO_ERR_ECP_RANDOM_FAILED;
+ goto cleanup;
+ }
+ }
+ while( mbedcrypto_mpi_cmp_int( r, 0 ) == 0 );
+
+ /*
+ * Step 5: derive MPI from hashed message
+ */
+ MBEDCRYPTO_MPI_CHK( derive_mpi( grp, &e, buf, blen ) );
+
+ /*
+ * Generate a random value to blind inv_mod in next step,
+ * avoiding a potential timing leak.
+ */
+ blind_tries = 0;
+ do
+ {
+ size_t n_size = ( grp->nbits + 7 ) / 8;
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_fill_random( &t, n_size, f_rng, p_rng ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_r( &t, 8 * n_size - grp->nbits ) );
+
+ /* See mbedcrypto_ecp_gen_keypair() */
+ if( ++blind_tries > 30 )
+ return( MBEDCRYPTO_ERR_ECP_RANDOM_FAILED );
+ }
+ while( mbedcrypto_mpi_cmp_int( &t, 1 ) < 0 ||
+ mbedcrypto_mpi_cmp_mpi( &t, &grp->N ) >= 0 );
+
+ /*
+ * Step 6: compute s = (e + r * d) / k = t (e + rd) / (kt) mod n
+ */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( s, r, d ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_mpi( &e, &e, s ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &e, &e, &t ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &k, &k, &t ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_inv_mod( s, &k, &grp->N ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( s, s, &e ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mod_mpi( s, s, &grp->N ) );
+
+ if( sign_tries++ > 10 )
+ {
+ ret = MBEDCRYPTO_ERR_ECP_RANDOM_FAILED;
+ goto cleanup;
+ }
+ }
+ while( mbedcrypto_mpi_cmp_int( s, 0 ) == 0 );
+
+cleanup:
+ mbedcrypto_ecp_point_free( &R );
+ mbedcrypto_mpi_free( &k ); mbedcrypto_mpi_free( &e ); mbedcrypto_mpi_free( &t );
+
+ return( ret );
+}
+#endif /* MBEDCRYPTO_ECDSA_SIGN_ALT */
+
+#if defined(MBEDCRYPTO_ECDSA_DETERMINISTIC)
+/*
+ * Deterministic signature wrapper
+ */
+int mbedcrypto_ecdsa_sign_det( mbedcrypto_ecp_group *grp, mbedcrypto_mpi *r, mbedcrypto_mpi *s,
+ const mbedcrypto_mpi *d, const unsigned char *buf, size_t blen,
+ mbedcrypto_md_type_t md_alg )
+{
+ int ret;
+ mbedcrypto_hmac_drbg_context rng_ctx;
+ unsigned char data[2 * MBEDCRYPTO_ECP_MAX_BYTES];
+ size_t grp_len = ( grp->nbits + 7 ) / 8;
+ const mbedcrypto_md_info_t *md_info;
+ mbedcrypto_mpi h;
+
+ if( ( md_info = mbedcrypto_md_info_from_type( md_alg ) ) == NULL )
+ return( MBEDCRYPTO_ERR_ECP_BAD_INPUT_DATA );
+
+ mbedcrypto_mpi_init( &h );
+ mbedcrypto_hmac_drbg_init( &rng_ctx );
+
+ /* Use private key and message hash (reduced) to initialize HMAC_DRBG */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_write_binary( d, data, grp_len ) );
+ MBEDCRYPTO_MPI_CHK( derive_mpi( grp, &h, buf, blen ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_write_binary( &h, data + grp_len, grp_len ) );
+ mbedcrypto_hmac_drbg_seed_buf( &rng_ctx, md_info, data, 2 * grp_len );
+
+ ret = mbedcrypto_ecdsa_sign( grp, r, s, d, buf, blen,
+ mbedcrypto_hmac_drbg_random, &rng_ctx );
+
+cleanup:
+ mbedcrypto_hmac_drbg_free( &rng_ctx );
+ mbedcrypto_mpi_free( &h );
+
+ return( ret );
+}
+#endif /* MBEDCRYPTO_ECDSA_DETERMINISTIC */
+
+#if !defined(MBEDCRYPTO_ECDSA_VERIFY_ALT)
+/*
+ * Verify ECDSA signature of hashed message (SEC1 4.1.4)
+ * Obviously, compared to SEC1 4.1.3, we skip step 2 (hash message)
+ */
+int mbedcrypto_ecdsa_verify( mbedcrypto_ecp_group *grp,
+ const unsigned char *buf, size_t blen,
+ const mbedcrypto_ecp_point *Q, const mbedcrypto_mpi *r, const mbedcrypto_mpi *s)
+{
+ int ret;
+ mbedcrypto_mpi e, s_inv, u1, u2;
+ mbedcrypto_ecp_point R;
+
+ mbedcrypto_ecp_point_init( &R );
+ mbedcrypto_mpi_init( &e ); mbedcrypto_mpi_init( &s_inv ); mbedcrypto_mpi_init( &u1 ); mbedcrypto_mpi_init( &u2 );
+
+ /* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */
+ if( grp->N.p == NULL )
+ return( MBEDCRYPTO_ERR_ECP_BAD_INPUT_DATA );
+
+ /*
+ * Step 1: make sure r and s are in range 1..n-1
+ */
+ if( mbedcrypto_mpi_cmp_int( r, 1 ) < 0 || mbedcrypto_mpi_cmp_mpi( r, &grp->N ) >= 0 ||
+ mbedcrypto_mpi_cmp_int( s, 1 ) < 0 || mbedcrypto_mpi_cmp_mpi( s, &grp->N ) >= 0 )
+ {
+ ret = MBEDCRYPTO_ERR_ECP_VERIFY_FAILED;
+ goto cleanup;
+ }
+
+ /*
+ * Additional precaution: make sure Q is valid
+ */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_ecp_check_pubkey( grp, Q ) );
+
+ /*
+ * Step 3: derive MPI from hashed message
+ */
+ MBEDCRYPTO_MPI_CHK( derive_mpi( grp, &e, buf, blen ) );
+
+ /*
+ * Step 4: u1 = e / s mod n, u2 = r / s mod n
+ */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_inv_mod( &s_inv, s, &grp->N ) );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &u1, &e, &s_inv ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mod_mpi( &u1, &u1, &grp->N ) );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &u2, r, &s_inv ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mod_mpi( &u2, &u2, &grp->N ) );
+
+ /*
+ * Step 5: R = u1 G + u2 Q
+ *
+ * Since we're not using any secret data, no need to pass a RNG to
+ * mbedcrypto_ecp_mul() for countermesures.
+ */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_ecp_muladd( grp, &R, &u1, &grp->G, &u2, Q ) );
+
+ if( mbedcrypto_ecp_is_zero( &R ) )
+ {
+ ret = MBEDCRYPTO_ERR_ECP_VERIFY_FAILED;
+ goto cleanup;
+ }
+
+ /*
+ * Step 6: convert xR to an integer (no-op)
+ * Step 7: reduce xR mod n (gives v)
+ */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mod_mpi( &R.X, &R.X, &grp->N ) );
+
+ /*
+ * Step 8: check if v (that is, R.X) is equal to r
+ */
+ if( mbedcrypto_mpi_cmp_mpi( &R.X, r ) != 0 )
+ {
+ ret = MBEDCRYPTO_ERR_ECP_VERIFY_FAILED;
+ goto cleanup;
+ }
+
+cleanup:
+ mbedcrypto_ecp_point_free( &R );
+ mbedcrypto_mpi_free( &e ); mbedcrypto_mpi_free( &s_inv ); mbedcrypto_mpi_free( &u1 ); mbedcrypto_mpi_free( &u2 );
+
+ return( ret );
+}
+#endif /* MBEDCRYPTO_ECDSA_VERIFY_ALT */
+
+/*
+ * Convert a signature (given by context) to ASN.1
+ */
+static int ecdsa_signature_to_asn1( const mbedcrypto_mpi *r, const mbedcrypto_mpi *s,
+ unsigned char *sig, size_t *slen )
+{
+ int ret;
+ unsigned char buf[MBEDCRYPTO_ECDSA_MAX_LEN];
+ unsigned char *p = buf + sizeof( buf );
+ size_t len = 0;
+
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_mpi( &p, buf, s ) );
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_mpi( &p, buf, r ) );
+
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_len( &p, buf, len ) );
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_tag( &p, buf,
+ MBEDCRYPTO_ASN1_CONSTRUCTED | MBEDCRYPTO_ASN1_SEQUENCE ) );
+
+ memcpy( sig, p, len );
+ *slen = len;
+
+ return( 0 );
+}
+
+/*
+ * Compute and write signature
+ */
+int mbedcrypto_ecdsa_write_signature( mbedcrypto_ecdsa_context *ctx, mbedcrypto_md_type_t md_alg,
+ const unsigned char *hash, size_t hlen,
+ unsigned char *sig, size_t *slen,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng )
+{
+ int ret;
+ mbedcrypto_mpi r, s;
+
+ mbedcrypto_mpi_init( &r );
+ mbedcrypto_mpi_init( &s );
+
+#if defined(MBEDCRYPTO_ECDSA_DETERMINISTIC)
+ (void) f_rng;
+ (void) p_rng;
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_ecdsa_sign_det( &ctx->grp, &r, &s, &ctx->d,
+ hash, hlen, md_alg ) );
+#else
+ (void) md_alg;
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_ecdsa_sign( &ctx->grp, &r, &s, &ctx->d,
+ hash, hlen, f_rng, p_rng ) );
+#endif
+
+ MBEDCRYPTO_MPI_CHK( ecdsa_signature_to_asn1( &r, &s, sig, slen ) );
+
+cleanup:
+ mbedcrypto_mpi_free( &r );
+ mbedcrypto_mpi_free( &s );
+
+ return( ret );
+}
+
+#if ! defined(MBEDCRYPTO_DEPRECATED_REMOVED) && \
+ defined(MBEDCRYPTO_ECDSA_DETERMINISTIC)
+int mbedcrypto_ecdsa_write_signature_det( mbedcrypto_ecdsa_context *ctx,
+ const unsigned char *hash, size_t hlen,
+ unsigned char *sig, size_t *slen,
+ mbedcrypto_md_type_t md_alg )
+{
+ return( mbedcrypto_ecdsa_write_signature( ctx, md_alg, hash, hlen, sig, slen,
+ NULL, NULL ) );
+}
+#endif
+
+/*
+ * Read and check signature
+ */
+int mbedcrypto_ecdsa_read_signature( mbedcrypto_ecdsa_context *ctx,
+ const unsigned char *hash, size_t hlen,
+ const unsigned char *sig, size_t slen )
+{
+ int ret;
+ unsigned char *p = (unsigned char *) sig;
+ const unsigned char *end = sig + slen;
+ size_t len;
+ mbedcrypto_mpi r, s;
+
+ mbedcrypto_mpi_init( &r );
+ mbedcrypto_mpi_init( &s );
+
+ if( ( ret = mbedcrypto_asn1_get_tag( &p, end, &len,
+ MBEDCRYPTO_ASN1_CONSTRUCTED | MBEDCRYPTO_ASN1_SEQUENCE ) ) != 0 )
+ {
+ ret += MBEDCRYPTO_ERR_ECP_BAD_INPUT_DATA;
+ goto cleanup;
+ }
+
+ if( p + len != end )
+ {
+ ret = MBEDCRYPTO_ERR_ECP_BAD_INPUT_DATA +
+ MBEDCRYPTO_ERR_ASN1_LENGTH_MISMATCH;
+ goto cleanup;
+ }
+
+ if( ( ret = mbedcrypto_asn1_get_mpi( &p, end, &r ) ) != 0 ||
+ ( ret = mbedcrypto_asn1_get_mpi( &p, end, &s ) ) != 0 )
+ {
+ ret += MBEDCRYPTO_ERR_ECP_BAD_INPUT_DATA;
+ goto cleanup;
+ }
+
+ if( ( ret = mbedcrypto_ecdsa_verify( &ctx->grp, hash, hlen,
+ &ctx->Q, &r, &s ) ) != 0 )
+ goto cleanup;
+
+ /* At this point we know that the buffer starts with a valid signature.
+ * Return 0 if the buffer just contains the signature, and a specific
+ * error code if the valid signature is followed by more data. */
+ if( p != end )
+ ret = MBEDCRYPTO_ERR_ECP_SIG_LEN_MISMATCH;
+
+cleanup:
+ mbedcrypto_mpi_free( &r );
+ mbedcrypto_mpi_free( &s );
+
+ return( ret );
+}
+
+#if !defined(MBEDCRYPTO_ECDSA_GENKEY_ALT)
+/*
+ * Generate key pair
+ */
+int mbedcrypto_ecdsa_genkey( mbedcrypto_ecdsa_context *ctx, mbedcrypto_ecp_group_id gid,
+ int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
+{
+ return( mbedcrypto_ecp_group_load( &ctx->grp, gid ) ||
+ mbedcrypto_ecp_gen_keypair( &ctx->grp, &ctx->d, &ctx->Q, f_rng, p_rng ) );
+}
+#endif /* MBEDCRYPTO_ECDSA_GENKEY_ALT */
+
+/*
+ * Set context from an mbedcrypto_ecp_keypair
+ */
+int mbedcrypto_ecdsa_from_keypair( mbedcrypto_ecdsa_context *ctx, const mbedcrypto_ecp_keypair *key )
+{
+ int ret;
+
+ if( ( ret = mbedcrypto_ecp_group_copy( &ctx->grp, &key->grp ) ) != 0 ||
+ ( ret = mbedcrypto_mpi_copy( &ctx->d, &key->d ) ) != 0 ||
+ ( ret = mbedcrypto_ecp_copy( &ctx->Q, &key->Q ) ) != 0 )
+ {
+ mbedcrypto_ecdsa_free( ctx );
+ }
+
+ return( ret );
+}
+
+/*
+ * Initialize context
+ */
+void mbedcrypto_ecdsa_init( mbedcrypto_ecdsa_context *ctx )
+{
+ mbedcrypto_ecp_keypair_init( ctx );
+}
+
+/*
+ * Free context
+ */
+void mbedcrypto_ecdsa_free( mbedcrypto_ecdsa_context *ctx )
+{
+ mbedcrypto_ecp_keypair_free( ctx );
+}
+
+#endif /* MBEDCRYPTO_ECDSA_C */
diff --git a/library/ecp.c b/library/ecp.c
new file mode 100644
index 0000000..d29c4a2
--- /dev/null
+++ b/library/ecp.c
@@ -0,0 +1,2203 @@
+/*
+ * Elliptic curves over GF(p): generic 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 Crypto (https://tls.mbed.org)
+ */
+
+/*
+ * References:
+ *
+ * SEC1 http://www.secg.org/index.php?action=secg,docs_secg
+ * GECC = Guide to Elliptic Curve Cryptography - Hankerson, Menezes, Vanstone
+ * FIPS 186-3 http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf
+ * RFC 4492 for the related TLS structures and constants
+ * RFC 7748 for the Curve448 and Curve25519 curve definitions
+ *
+ * [Curve25519] http://cr.yp.to/ecdh/curve25519-20060209.pdf
+ *
+ * [2] CORON, Jean-S'ebastien. Resistance against differential power analysis
+ * for elliptic curve cryptosystems. In : Cryptographic Hardware and
+ * Embedded Systems. Springer Berlin Heidelberg, 1999. p. 292-302.
+ * <http://link.springer.com/chapter/10.1007/3-540-48059-5_25>
+ *
+ * [3] HEDABOU, Mustapha, PINEL, Pierre, et B'EN'ETEAU, Lucien. A comb method to
+ * render ECC resistant against Side Channel Attacks. IACR Cryptology
+ * ePrint Archive, 2004, vol. 2004, p. 342.
+ * <http://eprint.iacr.org/2004/342.pdf>
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_ECP_C)
+
+#include "mbedcrypto/ecp.h"
+#include "mbedcrypto/threading.h"
+#include "mbedcrypto/platform_util.h"
+
+#include <string.h>
+
+#if !defined(MBEDCRYPTO_ECP_ALT)
+
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#include <stdlib.h>
+#include <stdio.h>
+#define mbedcrypto_printf printf
+#define mbedcrypto_calloc calloc
+#define mbedcrypto_free free
+#endif
+
+#include "mbedcrypto/ecp_internal.h"
+
+#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
+ !defined(inline) && !defined(__cplusplus)
+#define inline __inline
+#endif
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+/*
+ * Counts of point addition and doubling, and field multiplications.
+ * Used to test resistance of point multiplication to simple timing attacks.
+ */
+static unsigned long add_count, dbl_count, mul_count;
+#endif
+
+#if defined(MBEDCRYPTO_ECP_DP_SECP192R1_ENABLED) || \
+ defined(MBEDCRYPTO_ECP_DP_SECP224R1_ENABLED) || \
+ defined(MBEDCRYPTO_ECP_DP_SECP256R1_ENABLED) || \
+ defined(MBEDCRYPTO_ECP_DP_SECP384R1_ENABLED) || \
+ defined(MBEDCRYPTO_ECP_DP_SECP521R1_ENABLED) || \
+ defined(MBEDCRYPTO_ECP_DP_BP256R1_ENABLED) || \
+ defined(MBEDCRYPTO_ECP_DP_BP384R1_ENABLED) || \
+ defined(MBEDCRYPTO_ECP_DP_BP512R1_ENABLED) || \
+ defined(MBEDCRYPTO_ECP_DP_SECP192K1_ENABLED) || \
+ defined(MBEDCRYPTO_ECP_DP_SECP224K1_ENABLED) || \
+ defined(MBEDCRYPTO_ECP_DP_SECP256K1_ENABLED)
+#define ECP_SHORTWEIERSTRASS
+#endif
+
+#if defined(MBEDCRYPTO_ECP_DP_CURVE25519_ENABLED) || \
+ defined(MBEDCRYPTO_ECP_DP_CURVE448_ENABLED)
+#define ECP_MONTGOMERY
+#endif
+
+/*
+ * Curve types: internal for now, might be exposed later
+ */
+typedef enum
+{
+ ECP_TYPE_NONE = 0,
+ ECP_TYPE_SHORT_WEIERSTRASS, /* y^2 = x^3 + a x + b */
+ ECP_TYPE_MONTGOMERY, /* y^2 = x^3 + a x^2 + x */
+} ecp_curve_type;
+
+/*
+ * List of supported curves:
+ * - internal ID
+ * - TLS NamedCurve ID (RFC 4492 sec. 5.1.1, RFC 7071 sec. 2)
+ * - size in bits
+ * - readable name
+ *
+ * Curves are listed in order: largest curves first, and for a given size,
+ * fastest curves first. This provides the default order for the SSL module.
+ *
+ * Reminder: update profiles in x509_crt.c when adding a new curves!
+ */
+static const mbedcrypto_ecp_curve_info ecp_supported_curves[] =
+{
+#if defined(MBEDCRYPTO_ECP_DP_SECP521R1_ENABLED)
+ { MBEDCRYPTO_ECP_DP_SECP521R1, 25, 521, "secp521r1" },
+#endif
+#if defined(MBEDCRYPTO_ECP_DP_BP512R1_ENABLED)
+ { MBEDCRYPTO_ECP_DP_BP512R1, 28, 512, "brainpoolP512r1" },
+#endif
+#if defined(MBEDCRYPTO_ECP_DP_SECP384R1_ENABLED)
+ { MBEDCRYPTO_ECP_DP_SECP384R1, 24, 384, "secp384r1" },
+#endif
+#if defined(MBEDCRYPTO_ECP_DP_BP384R1_ENABLED)
+ { MBEDCRYPTO_ECP_DP_BP384R1, 27, 384, "brainpoolP384r1" },
+#endif
+#if defined(MBEDCRYPTO_ECP_DP_SECP256R1_ENABLED)
+ { MBEDCRYPTO_ECP_DP_SECP256R1, 23, 256, "secp256r1" },
+#endif
+#if defined(MBEDCRYPTO_ECP_DP_SECP256K1_ENABLED)
+ { MBEDCRYPTO_ECP_DP_SECP256K1, 22, 256, "secp256k1" },
+#endif
+#if defined(MBEDCRYPTO_ECP_DP_BP256R1_ENABLED)
+ { MBEDCRYPTO_ECP_DP_BP256R1, 26, 256, "brainpoolP256r1" },
+#endif
+#if defined(MBEDCRYPTO_ECP_DP_SECP224R1_ENABLED)
+ { MBEDCRYPTO_ECP_DP_SECP224R1, 21, 224, "secp224r1" },
+#endif
+#if defined(MBEDCRYPTO_ECP_DP_SECP224K1_ENABLED)
+ { MBEDCRYPTO_ECP_DP_SECP224K1, 20, 224, "secp224k1" },
+#endif
+#if defined(MBEDCRYPTO_ECP_DP_SECP192R1_ENABLED)
+ { MBEDCRYPTO_ECP_DP_SECP192R1, 19, 192, "secp192r1" },
+#endif
+#if defined(MBEDCRYPTO_ECP_DP_SECP192K1_ENABLED)
+ { MBEDCRYPTO_ECP_DP_SECP192K1, 18, 192, "secp192k1" },
+#endif
+ { MBEDCRYPTO_ECP_DP_NONE, 0, 0, NULL },
+};
+
+#define ECP_NB_CURVES sizeof( ecp_supported_curves ) / \
+ sizeof( ecp_supported_curves[0] )
+
+static mbedcrypto_ecp_group_id ecp_supported_grp_id[ECP_NB_CURVES];
+
+/*
+ * List of supported curves and associated info
+ */
+const mbedcrypto_ecp_curve_info *mbedcrypto_ecp_curve_list( void )
+{
+ return( ecp_supported_curves );
+}
+
+/*
+ * List of supported curves, group ID only
+ */
+const mbedcrypto_ecp_group_id *mbedcrypto_ecp_grp_id_list( void )
+{
+ static int init_done = 0;
+
+ if( ! init_done )
+ {
+ size_t i = 0;
+ const mbedcrypto_ecp_curve_info *curve_info;
+
+ for( curve_info = mbedcrypto_ecp_curve_list();
+ curve_info->grp_id != MBEDCRYPTO_ECP_DP_NONE;
+ curve_info++ )
+ {
+ ecp_supported_grp_id[i++] = curve_info->grp_id;
+ }
+ ecp_supported_grp_id[i] = MBEDCRYPTO_ECP_DP_NONE;
+
+ init_done = 1;
+ }
+
+ return( ecp_supported_grp_id );
+}
+
+/*
+ * Get the curve info for the internal identifier
+ */
+const mbedcrypto_ecp_curve_info *mbedcrypto_ecp_curve_info_from_grp_id( mbedcrypto_ecp_group_id grp_id )
+{
+ const mbedcrypto_ecp_curve_info *curve_info;
+
+ for( curve_info = mbedcrypto_ecp_curve_list();
+ curve_info->grp_id != MBEDCRYPTO_ECP_DP_NONE;
+ curve_info++ )
+ {
+ if( curve_info->grp_id == grp_id )
+ return( curve_info );
+ }
+
+ return( NULL );
+}
+
+/*
+ * Get the curve info from the TLS identifier
+ */
+const mbedcrypto_ecp_curve_info *mbedcrypto_ecp_curve_info_from_tls_id( uint16_t tls_id )
+{
+ const mbedcrypto_ecp_curve_info *curve_info;
+
+ for( curve_info = mbedcrypto_ecp_curve_list();
+ curve_info->grp_id != MBEDCRYPTO_ECP_DP_NONE;
+ curve_info++ )
+ {
+ if( curve_info->tls_id == tls_id )
+ return( curve_info );
+ }
+
+ return( NULL );
+}
+
+/*
+ * Get the curve info from the name
+ */
+const mbedcrypto_ecp_curve_info *mbedcrypto_ecp_curve_info_from_name( const char *name )
+{
+ const mbedcrypto_ecp_curve_info *curve_info;
+
+ for( curve_info = mbedcrypto_ecp_curve_list();
+ curve_info->grp_id != MBEDCRYPTO_ECP_DP_NONE;
+ curve_info++ )
+ {
+ if( strcmp( curve_info->name, name ) == 0 )
+ return( curve_info );
+ }
+
+ return( NULL );
+}
+
+/*
+ * Get the type of a curve
+ */
+static inline ecp_curve_type ecp_get_type( const mbedcrypto_ecp_group *grp )
+{
+ if( grp->G.X.p == NULL )
+ return( ECP_TYPE_NONE );
+
+ if( grp->G.Y.p == NULL )
+ return( ECP_TYPE_MONTGOMERY );
+ else
+ return( ECP_TYPE_SHORT_WEIERSTRASS );
+}
+
+/*
+ * Initialize (the components of) a point
+ */
+void mbedcrypto_ecp_point_init( mbedcrypto_ecp_point *pt )
+{
+ if( pt == NULL )
+ return;
+
+ mbedcrypto_mpi_init( &pt->X );
+ mbedcrypto_mpi_init( &pt->Y );
+ mbedcrypto_mpi_init( &pt->Z );
+}
+
+/*
+ * Initialize (the components of) a group
+ */
+void mbedcrypto_ecp_group_init( mbedcrypto_ecp_group *grp )
+{
+ if( grp == NULL )
+ return;
+
+ memset( grp, 0, sizeof( mbedcrypto_ecp_group ) );
+}
+
+/*
+ * Initialize (the components of) a key pair
+ */
+void mbedcrypto_ecp_keypair_init( mbedcrypto_ecp_keypair *key )
+{
+ if( key == NULL )
+ return;
+
+ mbedcrypto_ecp_group_init( &key->grp );
+ mbedcrypto_mpi_init( &key->d );
+ mbedcrypto_ecp_point_init( &key->Q );
+}
+
+/*
+ * Unallocate (the components of) a point
+ */
+void mbedcrypto_ecp_point_free( mbedcrypto_ecp_point *pt )
+{
+ if( pt == NULL )
+ return;
+
+ mbedcrypto_mpi_free( &( pt->X ) );
+ mbedcrypto_mpi_free( &( pt->Y ) );
+ mbedcrypto_mpi_free( &( pt->Z ) );
+}
+
+/*
+ * Unallocate (the components of) a group
+ */
+void mbedcrypto_ecp_group_free( mbedcrypto_ecp_group *grp )
+{
+ size_t i;
+
+ if( grp == NULL )
+ return;
+
+ if( grp->h != 1 )
+ {
+ mbedcrypto_mpi_free( &grp->P );
+ mbedcrypto_mpi_free( &grp->A );
+ mbedcrypto_mpi_free( &grp->B );
+ mbedcrypto_ecp_point_free( &grp->G );
+ mbedcrypto_mpi_free( &grp->N );
+ }
+
+ if( grp->T != NULL )
+ {
+ for( i = 0; i < grp->T_size; i++ )
+ mbedcrypto_ecp_point_free( &grp->T[i] );
+ mbedcrypto_free( grp->T );
+ }
+
+ mbedcrypto_platform_zeroize( grp, sizeof( mbedcrypto_ecp_group ) );
+}
+
+/*
+ * Unallocate (the components of) a key pair
+ */
+void mbedcrypto_ecp_keypair_free( mbedcrypto_ecp_keypair *key )
+{
+ if( key == NULL )
+ return;
+
+ mbedcrypto_ecp_group_free( &key->grp );
+ mbedcrypto_mpi_free( &key->d );
+ mbedcrypto_ecp_point_free( &key->Q );
+}
+
+/*
+ * Copy the contents of a point
+ */
+int mbedcrypto_ecp_copy( mbedcrypto_ecp_point *P, const mbedcrypto_ecp_point *Q )
+{
+ int ret;
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &P->X, &Q->X ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &P->Y, &Q->Y ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &P->Z, &Q->Z ) );
+
+cleanup:
+ return( ret );
+}
+
+/*
+ * Copy the contents of a group object
+ */
+int mbedcrypto_ecp_group_copy( mbedcrypto_ecp_group *dst, const mbedcrypto_ecp_group *src )
+{
+ return mbedcrypto_ecp_group_load( dst, src->id );
+}
+
+/*
+ * Set point to zero
+ */
+int mbedcrypto_ecp_set_zero( mbedcrypto_ecp_point *pt )
+{
+ int ret;
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_lset( &pt->X , 1 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_lset( &pt->Y , 1 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_lset( &pt->Z , 0 ) );
+
+cleanup:
+ return( ret );
+}
+
+/*
+ * Tell if a point is zero
+ */
+int mbedcrypto_ecp_is_zero( mbedcrypto_ecp_point *pt )
+{
+ return( mbedcrypto_mpi_cmp_int( &pt->Z, 0 ) == 0 );
+}
+
+/*
+ * Compare two points lazyly
+ */
+int mbedcrypto_ecp_point_cmp( const mbedcrypto_ecp_point *P,
+ const mbedcrypto_ecp_point *Q )
+{
+ if( mbedcrypto_mpi_cmp_mpi( &P->X, &Q->X ) == 0 &&
+ mbedcrypto_mpi_cmp_mpi( &P->Y, &Q->Y ) == 0 &&
+ mbedcrypto_mpi_cmp_mpi( &P->Z, &Q->Z ) == 0 )
+ {
+ return( 0 );
+ }
+
+ return( MBEDCRYPTO_ERR_ECP_BAD_INPUT_DATA );
+}
+
+/*
+ * Import a non-zero point from ASCII strings
+ */
+int mbedcrypto_ecp_point_read_string( mbedcrypto_ecp_point *P, int radix,
+ const char *x, const char *y )
+{
+ int ret;
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_string( &P->X, radix, x ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_string( &P->Y, radix, y ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_lset( &P->Z, 1 ) );
+
+cleanup:
+ return( ret );
+}
+
+/*
+ * Export a point into unsigned binary data (SEC1 2.3.3)
+ */
+int mbedcrypto_ecp_point_write_binary( const mbedcrypto_ecp_group *grp, const mbedcrypto_ecp_point *P,
+ int format, size_t *olen,
+ unsigned char *buf, size_t buflen )
+{
+ int ret = 0;
+ size_t plen;
+
+ if( format != MBEDCRYPTO_ECP_PF_UNCOMPRESSED &&
+ format != MBEDCRYPTO_ECP_PF_COMPRESSED )
+ return( MBEDCRYPTO_ERR_ECP_BAD_INPUT_DATA );
+
+ /*
+ * Common case: P == 0
+ */
+ if( mbedcrypto_mpi_cmp_int( &P->Z, 0 ) == 0 )
+ {
+ if( buflen < 1 )
+ return( MBEDCRYPTO_ERR_ECP_BUFFER_TOO_SMALL );
+
+ buf[0] = 0x00;
+ *olen = 1;
+
+ return( 0 );
+ }
+
+ plen = mbedcrypto_mpi_size( &grp->P );
+
+ if( format == MBEDCRYPTO_ECP_PF_UNCOMPRESSED )
+ {
+ *olen = 2 * plen + 1;
+
+ if( buflen < *olen )
+ return( MBEDCRYPTO_ERR_ECP_BUFFER_TOO_SMALL );
+
+ buf[0] = 0x04;
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_write_binary( &P->X, buf + 1, plen ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_write_binary( &P->Y, buf + 1 + plen, plen ) );
+ }
+ else if( format == MBEDCRYPTO_ECP_PF_COMPRESSED )
+ {
+ *olen = plen + 1;
+
+ if( buflen < *olen )
+ return( MBEDCRYPTO_ERR_ECP_BUFFER_TOO_SMALL );
+
+ buf[0] = 0x02 + mbedcrypto_mpi_get_bit( &P->Y, 0 );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_write_binary( &P->X, buf + 1, plen ) );
+ }
+
+cleanup:
+ return( ret );
+}
+
+/*
+ * Import a point from unsigned binary data (SEC1 2.3.4)
+ */
+int mbedcrypto_ecp_point_read_binary( const mbedcrypto_ecp_group *grp, mbedcrypto_ecp_point *pt,
+ const unsigned char *buf, size_t ilen )
+{
+ int ret;
+ size_t plen;
+
+ if( ilen < 1 )
+ return( MBEDCRYPTO_ERR_ECP_BAD_INPUT_DATA );
+
+ if( buf[0] == 0x00 )
+ {
+ if( ilen == 1 )
+ return( mbedcrypto_ecp_set_zero( pt ) );
+ else
+ return( MBEDCRYPTO_ERR_ECP_BAD_INPUT_DATA );
+ }
+
+ plen = mbedcrypto_mpi_size( &grp->P );
+
+ if( buf[0] != 0x04 )
+ return( MBEDCRYPTO_ERR_ECP_FEATURE_UNAVAILABLE );
+
+ if( ilen != 2 * plen + 1 )
+ return( MBEDCRYPTO_ERR_ECP_BAD_INPUT_DATA );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_binary( &pt->X, buf + 1, plen ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_binary( &pt->Y, buf + 1 + plen, plen ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_lset( &pt->Z, 1 ) );
+
+cleanup:
+ return( ret );
+}
+
+/*
+ * Import a point from a TLS ECPoint record (RFC 4492)
+ * struct {
+ * opaque point <1..2^8-1>;
+ * } ECPoint;
+ */
+int mbedcrypto_ecp_tls_read_point( const mbedcrypto_ecp_group *grp, mbedcrypto_ecp_point *pt,
+ const unsigned char **buf, size_t buf_len )
+{
+ unsigned char data_len;
+ const unsigned char *buf_start;
+
+ /*
+ * We must have at least two bytes (1 for length, at least one for data)
+ */
+ if( buf_len < 2 )
+ return( MBEDCRYPTO_ERR_ECP_BAD_INPUT_DATA );
+
+ data_len = *(*buf)++;
+ if( data_len < 1 || data_len > buf_len - 1 )
+ return( MBEDCRYPTO_ERR_ECP_BAD_INPUT_DATA );
+
+ /*
+ * Save buffer start for read_binary and update buf
+ */
+ buf_start = *buf;
+ *buf += data_len;
+
+ return mbedcrypto_ecp_point_read_binary( grp, pt, buf_start, data_len );
+}
+
+/*
+ * Export a point as a TLS ECPoint record (RFC 4492)
+ * struct {
+ * opaque point <1..2^8-1>;
+ * } ECPoint;
+ */
+int mbedcrypto_ecp_tls_write_point( const mbedcrypto_ecp_group *grp, const mbedcrypto_ecp_point *pt,
+ int format, size_t *olen,
+ unsigned char *buf, size_t blen )
+{
+ int ret;
+
+ /*
+ * buffer length must be at least one, for our length byte
+ */
+ if( blen < 1 )
+ return( MBEDCRYPTO_ERR_ECP_BAD_INPUT_DATA );
+
+ if( ( ret = mbedcrypto_ecp_point_write_binary( grp, pt, format,
+ olen, buf + 1, blen - 1) ) != 0 )
+ return( ret );
+
+ /*
+ * write length to the first byte and update total length
+ */
+ buf[0] = (unsigned char) *olen;
+ ++*olen;
+
+ return( 0 );
+}
+
+/*
+ * Set a group from an ECParameters record (RFC 4492)
+ */
+int mbedcrypto_ecp_tls_read_group( mbedcrypto_ecp_group *grp, const unsigned char **buf, size_t len )
+{
+ uint16_t tls_id;
+ const mbedcrypto_ecp_curve_info *curve_info;
+
+ /*
+ * We expect at least three bytes (see below)
+ */
+ if( len < 3 )
+ return( MBEDCRYPTO_ERR_ECP_BAD_INPUT_DATA );
+
+ /*
+ * First byte is curve_type; only named_curve is handled
+ */
+ if( *(*buf)++ != MBEDCRYPTO_ECP_TLS_NAMED_CURVE )
+ return( MBEDCRYPTO_ERR_ECP_BAD_INPUT_DATA );
+
+ /*
+ * Next two bytes are the namedcurve value
+ */
+ tls_id = *(*buf)++;
+ tls_id <<= 8;
+ tls_id |= *(*buf)++;
+
+ if( ( curve_info = mbedcrypto_ecp_curve_info_from_tls_id( tls_id ) ) == NULL )
+ return( MBEDCRYPTO_ERR_ECP_FEATURE_UNAVAILABLE );
+
+ return mbedcrypto_ecp_group_load( grp, curve_info->grp_id );
+}
+
+/*
+ * Write the ECParameters record corresponding to a group (RFC 4492)
+ */
+int mbedcrypto_ecp_tls_write_group( const mbedcrypto_ecp_group *grp, size_t *olen,
+ unsigned char *buf, size_t blen )
+{
+ const mbedcrypto_ecp_curve_info *curve_info;
+
+ if( ( curve_info = mbedcrypto_ecp_curve_info_from_grp_id( grp->id ) ) == NULL )
+ return( MBEDCRYPTO_ERR_ECP_BAD_INPUT_DATA );
+
+ /*
+ * We are going to write 3 bytes (see below)
+ */
+ *olen = 3;
+ if( blen < *olen )
+ return( MBEDCRYPTO_ERR_ECP_BUFFER_TOO_SMALL );
+
+ /*
+ * First byte is curve_type, always named_curve
+ */
+ *buf++ = MBEDCRYPTO_ECP_TLS_NAMED_CURVE;
+
+ /*
+ * Next two bytes are the namedcurve value
+ */
+ buf[0] = curve_info->tls_id >> 8;
+ buf[1] = curve_info->tls_id & 0xFF;
+
+ return( 0 );
+}
+
+/*
+ * Wrapper around fast quasi-modp functions, with fall-back to mbedcrypto_mpi_mod_mpi.
+ * See the documentation of struct mbedcrypto_ecp_group.
+ *
+ * This function is in the critial loop for mbedcrypto_ecp_mul, so pay attention to perf.
+ */
+static int ecp_modp( mbedcrypto_mpi *N, const mbedcrypto_ecp_group *grp )
+{
+ int ret;
+
+ if( grp->modp == NULL )
+ return( mbedcrypto_mpi_mod_mpi( N, N, &grp->P ) );
+
+ /* N->s < 0 is a much faster test, which fails only if N is 0 */
+ if( ( N->s < 0 && mbedcrypto_mpi_cmp_int( N, 0 ) != 0 ) ||
+ mbedcrypto_mpi_bitlen( N ) > 2 * grp->pbits )
+ {
+ return( MBEDCRYPTO_ERR_ECP_BAD_INPUT_DATA );
+ }
+
+ MBEDCRYPTO_MPI_CHK( grp->modp( N ) );
+
+ /* N->s < 0 is a much faster test, which fails only if N is 0 */
+ while( N->s < 0 && mbedcrypto_mpi_cmp_int( N, 0 ) != 0 )
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_mpi( N, N, &grp->P ) );
+
+ while( mbedcrypto_mpi_cmp_mpi( N, &grp->P ) >= 0 )
+ /* we known P, N and the result are positive */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_abs( N, N, &grp->P ) );
+
+cleanup:
+ return( ret );
+}
+
+/*
+ * Fast mod-p functions expect their argument to be in the 0..p^2 range.
+ *
+ * In order to guarantee that, we need to ensure that operands of
+ * mbedcrypto_mpi_mul_mpi are in the 0..p range. So, after each operation we will
+ * bring the result back to this range.
+ *
+ * The following macros are shortcuts for doing that.
+ */
+
+/*
+ * Reduce a mbedcrypto_mpi mod p in-place, general case, to use after mbedcrypto_mpi_mul_mpi
+ */
+#if defined(MBEDCRYPTO_SELF_TEST)
+#define INC_MUL_COUNT mul_count++;
+#else
+#define INC_MUL_COUNT
+#endif
+
+#define MOD_MUL( N ) do { MBEDCRYPTO_MPI_CHK( ecp_modp( &N, grp ) ); INC_MUL_COUNT } \
+ while( 0 )
+
+/*
+ * Reduce a mbedcrypto_mpi mod p in-place, to use after mbedcrypto_mpi_sub_mpi
+ * N->s < 0 is a very fast test, which fails only if N is 0
+ */
+#define MOD_SUB( N ) \
+ while( N.s < 0 && mbedcrypto_mpi_cmp_int( &N, 0 ) != 0 ) \
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_mpi( &N, &N, &grp->P ) )
+
+/*
+ * Reduce a mbedcrypto_mpi mod p in-place, to use after mbedcrypto_mpi_add_mpi and mbedcrypto_mpi_mul_int.
+ * We known P, N and the result are positive, so sub_abs is correct, and
+ * a bit faster.
+ */
+#define MOD_ADD( N ) \
+ while( mbedcrypto_mpi_cmp_mpi( &N, &grp->P ) >= 0 ) \
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_abs( &N, &N, &grp->P ) )
+
+#if defined(ECP_SHORTWEIERSTRASS)
+/*
+ * For curves in short Weierstrass form, we do all the internal operations in
+ * Jacobian coordinates.
+ *
+ * For multiplication, we'll use a comb method with coutermeasueres against
+ * SPA, hence timing attacks.
+ */
+
+/*
+ * Normalize jacobian coordinates so that Z == 0 || Z == 1 (GECC 3.2.1)
+ * Cost: 1N := 1I + 3M + 1S
+ */
+static int ecp_normalize_jac( const mbedcrypto_ecp_group *grp, mbedcrypto_ecp_point *pt )
+{
+ int ret;
+ mbedcrypto_mpi Zi, ZZi;
+
+ if( mbedcrypto_mpi_cmp_int( &pt->Z, 0 ) == 0 )
+ return( 0 );
+
+#if defined(MBEDCRYPTO_ECP_NORMALIZE_JAC_ALT)
+ if ( mbedcrypto_internal_ecp_grp_capable( grp ) )
+ {
+ return mbedcrypto_internal_ecp_normalize_jac( grp, pt );
+ }
+#endif /* MBEDCRYPTO_ECP_NORMALIZE_JAC_ALT */
+ mbedcrypto_mpi_init( &Zi ); mbedcrypto_mpi_init( &ZZi );
+
+ /*
+ * X = X / Z^2 mod p
+ */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_inv_mod( &Zi, &pt->Z, &grp->P ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &ZZi, &Zi, &Zi ) ); MOD_MUL( ZZi );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &pt->X, &pt->X, &ZZi ) ); MOD_MUL( pt->X );
+
+ /*
+ * Y = Y / Z^3 mod p
+ */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &pt->Y, &pt->Y, &ZZi ) ); MOD_MUL( pt->Y );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &pt->Y, &pt->Y, &Zi ) ); MOD_MUL( pt->Y );
+
+ /*
+ * Z = 1
+ */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_lset( &pt->Z, 1 ) );
+
+cleanup:
+
+ mbedcrypto_mpi_free( &Zi ); mbedcrypto_mpi_free( &ZZi );
+
+ return( ret );
+}
+
+/*
+ * Normalize jacobian coordinates of an array of (pointers to) points,
+ * using Montgomery's trick to perform only one inversion mod P.
+ * (See for example Cohen's "A Course in Computational Algebraic Number
+ * Theory", Algorithm 10.3.4.)
+ *
+ * Warning: fails (returning an error) if one of the points is zero!
+ * This should never happen, see choice of w in ecp_mul_comb().
+ *
+ * Cost: 1N(t) := 1I + (6t - 3)M + 1S
+ */
+static int ecp_normalize_jac_many( const mbedcrypto_ecp_group *grp,
+ mbedcrypto_ecp_point *T[], size_t t_len )
+{
+ int ret;
+ size_t i;
+ mbedcrypto_mpi *c, u, Zi, ZZi;
+
+ if( t_len < 2 )
+ return( ecp_normalize_jac( grp, *T ) );
+
+#if defined(MBEDCRYPTO_ECP_NORMALIZE_JAC_MANY_ALT)
+ if ( mbedcrypto_internal_ecp_grp_capable( grp ) )
+ {
+ return mbedcrypto_internal_ecp_normalize_jac_many(grp, T, t_len);
+ }
+#endif
+
+ if( ( c = mbedcrypto_calloc( t_len, sizeof( mbedcrypto_mpi ) ) ) == NULL )
+ return( MBEDCRYPTO_ERR_ECP_ALLOC_FAILED );
+
+ mbedcrypto_mpi_init( &u ); mbedcrypto_mpi_init( &Zi ); mbedcrypto_mpi_init( &ZZi );
+
+ /*
+ * c[i] = Z_0 * ... * Z_i
+ */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &c[0], &T[0]->Z ) );
+ for( i = 1; i < t_len; i++ )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &c[i], &c[i-1], &T[i]->Z ) );
+ MOD_MUL( c[i] );
+ }
+
+ /*
+ * u = 1 / (Z_0 * ... * Z_n) mod P
+ */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_inv_mod( &u, &c[t_len-1], &grp->P ) );
+
+ for( i = t_len - 1; ; i-- )
+ {
+ /*
+ * Zi = 1 / Z_i mod p
+ * u = 1 / (Z_0 * ... * Z_i) mod P
+ */
+ if( i == 0 ) {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &Zi, &u ) );
+ }
+ else
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &Zi, &u, &c[i-1] ) ); MOD_MUL( Zi );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &u, &u, &T[i]->Z ) ); MOD_MUL( u );
+ }
+
+ /*
+ * proceed as in normalize()
+ */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &ZZi, &Zi, &Zi ) ); MOD_MUL( ZZi );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &T[i]->X, &T[i]->X, &ZZi ) ); MOD_MUL( T[i]->X );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &T[i]->Y, &T[i]->Y, &ZZi ) ); MOD_MUL( T[i]->Y );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &T[i]->Y, &T[i]->Y, &Zi ) ); MOD_MUL( T[i]->Y );
+
+ /*
+ * Post-precessing: reclaim some memory by shrinking coordinates
+ * - not storing Z (always 1)
+ * - shrinking other coordinates, but still keeping the same number of
+ * limbs as P, as otherwise it will too likely be regrown too fast.
+ */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shrink( &T[i]->X, grp->P.n ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shrink( &T[i]->Y, grp->P.n ) );
+ mbedcrypto_mpi_free( &T[i]->Z );
+
+ if( i == 0 )
+ break;
+ }
+
+cleanup:
+
+ mbedcrypto_mpi_free( &u ); mbedcrypto_mpi_free( &Zi ); mbedcrypto_mpi_free( &ZZi );
+ for( i = 0; i < t_len; i++ )
+ mbedcrypto_mpi_free( &c[i] );
+ mbedcrypto_free( c );
+
+ return( ret );
+}
+
+/*
+ * Conditional point inversion: Q -> -Q = (Q.X, -Q.Y, Q.Z) without leak.
+ * "inv" must be 0 (don't invert) or 1 (invert) or the result will be invalid
+ */
+static int ecp_safe_invert_jac( const mbedcrypto_ecp_group *grp,
+ mbedcrypto_ecp_point *Q,
+ unsigned char inv )
+{
+ int ret;
+ unsigned char nonzero;
+ mbedcrypto_mpi mQY;
+
+ mbedcrypto_mpi_init( &mQY );
+
+ /* Use the fact that -Q.Y mod P = P - Q.Y unless Q.Y == 0 */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &mQY, &grp->P, &Q->Y ) );
+ nonzero = mbedcrypto_mpi_cmp_int( &Q->Y, 0 ) != 0;
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_safe_cond_assign( &Q->Y, &mQY, inv & nonzero ) );
+
+cleanup:
+ mbedcrypto_mpi_free( &mQY );
+
+ return( ret );
+}
+
+/*
+ * Point doubling R = 2 P, Jacobian coordinates
+ *
+ * Based on http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-1998-cmo-2 .
+ *
+ * We follow the variable naming fairly closely. The formula variations that trade a MUL for a SQR
+ * (plus a few ADDs) aren't useful as our bignum implementation doesn't distinguish squaring.
+ *
+ * Standard optimizations are applied when curve parameter A is one of { 0, -3 }.
+ *
+ * Cost: 1D := 3M + 4S (A == 0)
+ * 4M + 4S (A == -3)
+ * 3M + 6S + 1a otherwise
+ */
+static int ecp_double_jac( const mbedcrypto_ecp_group *grp, mbedcrypto_ecp_point *R,
+ const mbedcrypto_ecp_point *P )
+{
+ int ret;
+ mbedcrypto_mpi M, S, T, U;
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+ dbl_count++;
+#endif
+
+#if defined(MBEDCRYPTO_ECP_DOUBLE_JAC_ALT)
+ if ( mbedcrypto_internal_ecp_grp_capable( grp ) )
+ {
+ return mbedcrypto_internal_ecp_double_jac( grp, R, P );
+ }
+#endif /* MBEDCRYPTO_ECP_DOUBLE_JAC_ALT */
+
+ mbedcrypto_mpi_init( &M ); mbedcrypto_mpi_init( &S ); mbedcrypto_mpi_init( &T ); mbedcrypto_mpi_init( &U );
+
+ /* Special case for A = -3 */
+ if( grp->A.p == NULL )
+ {
+ /* M = 3(X + Z^2)(X - Z^2) */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &S, &P->Z, &P->Z ) ); MOD_MUL( S );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_mpi( &T, &P->X, &S ) ); MOD_ADD( T );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &U, &P->X, &S ) ); MOD_SUB( U );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &S, &T, &U ) ); MOD_MUL( S );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_int( &M, &S, 3 ) ); MOD_ADD( M );
+ }
+ else
+ {
+ /* M = 3.X^2 */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &S, &P->X, &P->X ) ); MOD_MUL( S );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_int( &M, &S, 3 ) ); MOD_ADD( M );
+
+ /* Optimize away for "koblitz" curves with A = 0 */
+ if( mbedcrypto_mpi_cmp_int( &grp->A, 0 ) != 0 )
+ {
+ /* M += A.Z^4 */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &S, &P->Z, &P->Z ) ); MOD_MUL( S );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &T, &S, &S ) ); MOD_MUL( T );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &S, &T, &grp->A ) ); MOD_MUL( S );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_mpi( &M, &M, &S ) ); MOD_ADD( M );
+ }
+ }
+
+ /* S = 4.X.Y^2 */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &T, &P->Y, &P->Y ) ); MOD_MUL( T );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_l( &T, 1 ) ); MOD_ADD( T );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &S, &P->X, &T ) ); MOD_MUL( S );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_l( &S, 1 ) ); MOD_ADD( S );
+
+ /* U = 8.Y^4 */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &U, &T, &T ) ); MOD_MUL( U );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_l( &U, 1 ) ); MOD_ADD( U );
+
+ /* T = M^2 - 2.S */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &T, &M, &M ) ); MOD_MUL( T );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &T, &T, &S ) ); MOD_SUB( T );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &T, &T, &S ) ); MOD_SUB( T );
+
+ /* S = M(S - T) - U */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &S, &S, &T ) ); MOD_SUB( S );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &S, &S, &M ) ); MOD_MUL( S );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &S, &S, &U ) ); MOD_SUB( S );
+
+ /* U = 2.Y.Z */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &U, &P->Y, &P->Z ) ); MOD_MUL( U );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_l( &U, 1 ) ); MOD_ADD( U );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &R->X, &T ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &R->Y, &S ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &R->Z, &U ) );
+
+cleanup:
+ mbedcrypto_mpi_free( &M ); mbedcrypto_mpi_free( &S ); mbedcrypto_mpi_free( &T ); mbedcrypto_mpi_free( &U );
+
+ return( ret );
+}
+
+/*
+ * Addition: R = P + Q, mixed affine-Jacobian coordinates (GECC 3.22)
+ *
+ * The coordinates of Q must be normalized (= affine),
+ * but those of P don't need to. R is not normalized.
+ *
+ * Special cases: (1) P or Q is zero, (2) R is zero, (3) P == Q.
+ * None of these cases can happen as intermediate step in ecp_mul_comb():
+ * - at each step, P, Q and R are multiples of the base point, the factor
+ * being less than its order, so none of them is zero;
+ * - Q is an odd multiple of the base point, P an even multiple,
+ * due to the choice of precomputed points in the modified comb method.
+ * So branches for these cases do not leak secret information.
+ *
+ * We accept Q->Z being unset (saving memory in tables) as meaning 1.
+ *
+ * Cost: 1A := 8M + 3S
+ */
+static int ecp_add_mixed( const mbedcrypto_ecp_group *grp, mbedcrypto_ecp_point *R,
+ const mbedcrypto_ecp_point *P, const mbedcrypto_ecp_point *Q )
+{
+ int ret;
+ mbedcrypto_mpi T1, T2, T3, T4, X, Y, Z;
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+ add_count++;
+#endif
+
+#if defined(MBEDCRYPTO_ECP_ADD_MIXED_ALT)
+ if ( mbedcrypto_internal_ecp_grp_capable( grp ) )
+ {
+ return mbedcrypto_internal_ecp_add_mixed( grp, R, P, Q );
+ }
+#endif /* MBEDCRYPTO_ECP_ADD_MIXED_ALT */
+
+ /*
+ * Trivial cases: P == 0 or Q == 0 (case 1)
+ */
+ if( mbedcrypto_mpi_cmp_int( &P->Z, 0 ) == 0 )
+ return( mbedcrypto_ecp_copy( R, Q ) );
+
+ if( Q->Z.p != NULL && mbedcrypto_mpi_cmp_int( &Q->Z, 0 ) == 0 )
+ return( mbedcrypto_ecp_copy( R, P ) );
+
+ /*
+ * Make sure Q coordinates are normalized
+ */
+ if( Q->Z.p != NULL && mbedcrypto_mpi_cmp_int( &Q->Z, 1 ) != 0 )
+ return( MBEDCRYPTO_ERR_ECP_BAD_INPUT_DATA );
+
+ mbedcrypto_mpi_init( &T1 ); mbedcrypto_mpi_init( &T2 ); mbedcrypto_mpi_init( &T3 ); mbedcrypto_mpi_init( &T4 );
+ mbedcrypto_mpi_init( &X ); mbedcrypto_mpi_init( &Y ); mbedcrypto_mpi_init( &Z );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &T1, &P->Z, &P->Z ) ); MOD_MUL( T1 );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &T2, &T1, &P->Z ) ); MOD_MUL( T2 );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &T1, &T1, &Q->X ) ); MOD_MUL( T1 );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &T2, &T2, &Q->Y ) ); MOD_MUL( T2 );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &T1, &T1, &P->X ) ); MOD_SUB( T1 );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &T2, &T2, &P->Y ) ); MOD_SUB( T2 );
+
+ /* Special cases (2) and (3) */
+ if( mbedcrypto_mpi_cmp_int( &T1, 0 ) == 0 )
+ {
+ if( mbedcrypto_mpi_cmp_int( &T2, 0 ) == 0 )
+ {
+ ret = ecp_double_jac( grp, R, P );
+ goto cleanup;
+ }
+ else
+ {
+ ret = mbedcrypto_ecp_set_zero( R );
+ goto cleanup;
+ }
+ }
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &Z, &P->Z, &T1 ) ); MOD_MUL( Z );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &T3, &T1, &T1 ) ); MOD_MUL( T3 );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &T4, &T3, &T1 ) ); MOD_MUL( T4 );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &T3, &T3, &P->X ) ); MOD_MUL( T3 );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_int( &T1, &T3, 2 ) ); MOD_ADD( T1 );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &X, &T2, &T2 ) ); MOD_MUL( X );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &X, &X, &T1 ) ); MOD_SUB( X );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &X, &X, &T4 ) ); MOD_SUB( X );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &T3, &T3, &X ) ); MOD_SUB( T3 );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &T3, &T3, &T2 ) ); MOD_MUL( T3 );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &T4, &T4, &P->Y ) ); MOD_MUL( T4 );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &Y, &T3, &T4 ) ); MOD_SUB( Y );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &R->X, &X ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &R->Y, &Y ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &R->Z, &Z ) );
+
+cleanup:
+
+ mbedcrypto_mpi_free( &T1 ); mbedcrypto_mpi_free( &T2 ); mbedcrypto_mpi_free( &T3 ); mbedcrypto_mpi_free( &T4 );
+ mbedcrypto_mpi_free( &X ); mbedcrypto_mpi_free( &Y ); mbedcrypto_mpi_free( &Z );
+
+ return( ret );
+}
+
+/*
+ * Randomize jacobian coordinates:
+ * (X, Y, Z) -> (l^2 X, l^3 Y, l Z) for random l
+ * This is sort of the reverse operation of ecp_normalize_jac().
+ *
+ * This countermeasure was first suggested in [2].
+ */
+static int ecp_randomize_jac( const mbedcrypto_ecp_group *grp, mbedcrypto_ecp_point *pt,
+ int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
+{
+ int ret;
+ mbedcrypto_mpi l, ll;
+ size_t p_size;
+ int count = 0;
+
+#if defined(MBEDCRYPTO_ECP_RANDOMIZE_JAC_ALT)
+ if ( mbedcrypto_internal_ecp_grp_capable( grp ) )
+ {
+ return mbedcrypto_internal_ecp_randomize_jac( grp, pt, f_rng, p_rng );
+ }
+#endif /* MBEDCRYPTO_ECP_RANDOMIZE_JAC_ALT */
+
+ p_size = ( grp->pbits + 7 ) / 8;
+ mbedcrypto_mpi_init( &l ); mbedcrypto_mpi_init( &ll );
+
+ /* Generate l such that 1 < l < p */
+ do
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_fill_random( &l, p_size, f_rng, p_rng ) );
+
+ while( mbedcrypto_mpi_cmp_mpi( &l, &grp->P ) >= 0 )
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_r( &l, 1 ) );
+
+ if( count++ > 10 )
+ return( MBEDCRYPTO_ERR_ECP_RANDOM_FAILED );
+ }
+ while( mbedcrypto_mpi_cmp_int( &l, 1 ) <= 0 );
+
+ /* Z = l * Z */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &pt->Z, &pt->Z, &l ) ); MOD_MUL( pt->Z );
+
+ /* X = l^2 * X */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &ll, &l, &l ) ); MOD_MUL( ll );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &pt->X, &pt->X, &ll ) ); MOD_MUL( pt->X );
+
+ /* Y = l^3 * Y */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &ll, &ll, &l ) ); MOD_MUL( ll );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &pt->Y, &pt->Y, &ll ) ); MOD_MUL( pt->Y );
+
+cleanup:
+ mbedcrypto_mpi_free( &l ); mbedcrypto_mpi_free( &ll );
+
+ return( ret );
+}
+
+/*
+ * Check and define parameters used by the comb method (see below for details)
+ */
+#if MBEDCRYPTO_ECP_WINDOW_SIZE < 2 || MBEDCRYPTO_ECP_WINDOW_SIZE > 7
+#error "MBEDCRYPTO_ECP_WINDOW_SIZE out of bounds"
+#endif
+
+/* d = ceil( n / w ) */
+#define COMB_MAX_D ( MBEDCRYPTO_ECP_MAX_BITS + 1 ) / 2
+
+/* number of precomputed points */
+#define COMB_MAX_PRE ( 1 << ( MBEDCRYPTO_ECP_WINDOW_SIZE - 1 ) )
+
+/*
+ * Compute the representation of m that will be used with our comb method.
+ *
+ * The basic comb method is described in GECC 3.44 for example. We use a
+ * modified version that provides resistance to SPA by avoiding zero
+ * digits in the representation as in [3]. We modify the method further by
+ * requiring that all K_i be odd, which has the small cost that our
+ * representation uses one more K_i, due to carries.
+ *
+ * Also, for the sake of compactness, only the seven low-order bits of x[i]
+ * are used to represent K_i, and the msb of x[i] encodes the the sign (s_i in
+ * the paper): it is set if and only if if s_i == -1;
+ *
+ * Calling conventions:
+ * - x is an array of size d + 1
+ * - w is the size, ie number of teeth, of the comb, and must be between
+ * 2 and 7 (in practice, between 2 and MBEDCRYPTO_ECP_WINDOW_SIZE)
+ * - m is the MPI, expected to be odd and such that bitlength(m) <= w * d
+ * (the result will be incorrect if these assumptions are not satisfied)
+ */
+static void ecp_comb_fixed( unsigned char x[], size_t d,
+ unsigned char w, const mbedcrypto_mpi *m )
+{
+ size_t i, j;
+ unsigned char c, cc, adjust;
+
+ memset( x, 0, d+1 );
+
+ /* First get the classical comb values (except for x_d = 0) */
+ for( i = 0; i < d; i++ )
+ for( j = 0; j < w; j++ )
+ x[i] |= mbedcrypto_mpi_get_bit( m, i + d * j ) << j;
+
+ /* Now make sure x_1 .. x_d are odd */
+ c = 0;
+ for( i = 1; i <= d; i++ )
+ {
+ /* Add carry and update it */
+ cc = x[i] & c;
+ x[i] = x[i] ^ c;
+ c = cc;
+
+ /* Adjust if needed, avoiding branches */
+ adjust = 1 - ( x[i] & 0x01 );
+ c |= x[i] & ( x[i-1] * adjust );
+ x[i] = x[i] ^ ( x[i-1] * adjust );
+ x[i-1] |= adjust << 7;
+ }
+}
+
+/*
+ * Precompute points for the comb method
+ *
+ * If i = i_{w-1} ... i_1 is the binary representation of i, then
+ * T[i] = i_{w-1} 2^{(w-1)d} P + ... + i_1 2^d P + P
+ *
+ * T must be able to hold 2^{w - 1} elements
+ *
+ * Cost: d(w-1) D + (2^{w-1} - 1) A + 1 N(w-1) + 1 N(2^{w-1} - 1)
+ */
+static int ecp_precompute_comb( const mbedcrypto_ecp_group *grp,
+ mbedcrypto_ecp_point T[], const mbedcrypto_ecp_point *P,
+ unsigned char w, size_t d )
+{
+ int ret;
+ unsigned char i, k;
+ size_t j;
+ mbedcrypto_ecp_point *cur, *TT[COMB_MAX_PRE - 1];
+
+ /*
+ * Set T[0] = P and
+ * T[2^{l-1}] = 2^{dl} P for l = 1 .. w-1 (this is not the final value)
+ */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_ecp_copy( &T[0], P ) );
+
+ k = 0;
+ for( i = 1; i < ( 1U << ( w - 1 ) ); i <<= 1 )
+ {
+ cur = T + i;
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_ecp_copy( cur, T + ( i >> 1 ) ) );
+ for( j = 0; j < d; j++ )
+ MBEDCRYPTO_MPI_CHK( ecp_double_jac( grp, cur, cur ) );
+
+ TT[k++] = cur;
+ }
+
+ MBEDCRYPTO_MPI_CHK( ecp_normalize_jac_many( grp, TT, k ) );
+
+ /*
+ * Compute the remaining ones using the minimal number of additions
+ * Be careful to update T[2^l] only after using it!
+ */
+ k = 0;
+ for( i = 1; i < ( 1U << ( w - 1 ) ); i <<= 1 )
+ {
+ j = i;
+ while( j-- )
+ {
+ MBEDCRYPTO_MPI_CHK( ecp_add_mixed( grp, &T[i + j], &T[j], &T[i] ) );
+ TT[k++] = &T[i + j];
+ }
+ }
+
+ MBEDCRYPTO_MPI_CHK( ecp_normalize_jac_many( grp, TT, k ) );
+
+cleanup:
+
+ return( ret );
+}
+
+/*
+ * Select precomputed point: R = sign(i) * T[ abs(i) / 2 ]
+ */
+static int ecp_select_comb( const mbedcrypto_ecp_group *grp, mbedcrypto_ecp_point *R,
+ const mbedcrypto_ecp_point T[], unsigned char t_len,
+ unsigned char i )
+{
+ int ret;
+ unsigned char ii, j;
+
+ /* Ignore the "sign" bit and scale down */
+ ii = ( i & 0x7Fu ) >> 1;
+
+ /* Read the whole table to thwart cache-based timing attacks */
+ for( j = 0; j < t_len; j++ )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_safe_cond_assign( &R->X, &T[j].X, j == ii ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_safe_cond_assign( &R->Y, &T[j].Y, j == ii ) );
+ }
+
+ /* Safely invert result if i is "negative" */
+ MBEDCRYPTO_MPI_CHK( ecp_safe_invert_jac( grp, R, i >> 7 ) );
+
+cleanup:
+ return( ret );
+}
+
+/*
+ * Core multiplication algorithm for the (modified) comb method.
+ * This part is actually common with the basic comb method (GECC 3.44)
+ *
+ * Cost: d A + d D + 1 R
+ */
+static int ecp_mul_comb_core( const mbedcrypto_ecp_group *grp, mbedcrypto_ecp_point *R,
+ const mbedcrypto_ecp_point T[], unsigned char t_len,
+ const unsigned char x[], size_t d,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng )
+{
+ int ret;
+ mbedcrypto_ecp_point Txi;
+ size_t i;
+
+ mbedcrypto_ecp_point_init( &Txi );
+
+ /* Start with a non-zero point and randomize its coordinates */
+ i = d;
+ MBEDCRYPTO_MPI_CHK( ecp_select_comb( grp, R, T, t_len, x[i] ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_lset( &R->Z, 1 ) );
+ if( f_rng != 0 )
+ MBEDCRYPTO_MPI_CHK( ecp_randomize_jac( grp, R, f_rng, p_rng ) );
+
+ while( i-- != 0 )
+ {
+ MBEDCRYPTO_MPI_CHK( ecp_double_jac( grp, R, R ) );
+ MBEDCRYPTO_MPI_CHK( ecp_select_comb( grp, &Txi, T, t_len, x[i] ) );
+ MBEDCRYPTO_MPI_CHK( ecp_add_mixed( grp, R, R, &Txi ) );
+ }
+
+cleanup:
+
+ mbedcrypto_ecp_point_free( &Txi );
+
+ return( ret );
+}
+
+/*
+ * Multiplication using the comb method,
+ * for curves in short Weierstrass form
+ */
+static int ecp_mul_comb( mbedcrypto_ecp_group *grp, mbedcrypto_ecp_point *R,
+ const mbedcrypto_mpi *m, const mbedcrypto_ecp_point *P,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng )
+{
+ int ret;
+ unsigned char w, m_is_odd, p_eq_g, pre_len, i;
+ size_t d;
+ unsigned char k[COMB_MAX_D + 1];
+ mbedcrypto_ecp_point *T;
+ mbedcrypto_mpi M, mm;
+
+ mbedcrypto_mpi_init( &M );
+ mbedcrypto_mpi_init( &mm );
+
+ /* we need N to be odd to trnaform m in an odd number, check now */
+ if( mbedcrypto_mpi_get_bit( &grp->N, 0 ) != 1 )
+ return( MBEDCRYPTO_ERR_ECP_BAD_INPUT_DATA );
+
+ /*
+ * Minimize the number of multiplications, that is minimize
+ * 10 * d * w + 18 * 2^(w-1) + 11 * d + 7 * w, with d = ceil( nbits / w )
+ * (see costs of the various parts, with 1S = 1M)
+ */
+ w = grp->nbits >= 384 ? 5 : 4;
+
+ /*
+ * If P == G, pre-compute a bit more, since this may be re-used later.
+ * Just adding one avoids upping the cost of the first mul too much,
+ * and the memory cost too.
+ */
+#if MBEDCRYPTO_ECP_FIXED_POINT_OPTIM == 1
+ p_eq_g = ( mbedcrypto_mpi_cmp_mpi( &P->Y, &grp->G.Y ) == 0 &&
+ mbedcrypto_mpi_cmp_mpi( &P->X, &grp->G.X ) == 0 );
+ if( p_eq_g )
+ w++;
+#else
+ p_eq_g = 0;
+#endif
+
+ /*
+ * Make sure w is within bounds.
+ * (The last test is useful only for very small curves in the test suite.)
+ */
+ if( w > MBEDCRYPTO_ECP_WINDOW_SIZE )
+ w = MBEDCRYPTO_ECP_WINDOW_SIZE;
+ if( w >= grp->nbits )
+ w = 2;
+
+ /* Other sizes that depend on w */
+ pre_len = 1U << ( w - 1 );
+ d = ( grp->nbits + w - 1 ) / w;
+
+ /*
+ * Prepare precomputed points: if P == G we want to
+ * use grp->T if already initialized, or initialize it.
+ */
+ T = p_eq_g ? grp->T : NULL;
+
+ if( T == NULL )
+ {
+ T = mbedcrypto_calloc( pre_len, sizeof( mbedcrypto_ecp_point ) );
+ if( T == NULL )
+ {
+ ret = MBEDCRYPTO_ERR_ECP_ALLOC_FAILED;
+ goto cleanup;
+ }
+
+ MBEDCRYPTO_MPI_CHK( ecp_precompute_comb( grp, T, P, w, d ) );
+
+ if( p_eq_g )
+ {
+ grp->T = T;
+ grp->T_size = pre_len;
+ }
+ }
+
+ /*
+ * Make sure M is odd (M = m or M = N - m, since N is odd)
+ * using the fact that m * P = - (N - m) * P
+ */
+ m_is_odd = ( mbedcrypto_mpi_get_bit( m, 0 ) == 1 );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &M, m ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &mm, &grp->N, m ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_safe_cond_assign( &M, &mm, ! m_is_odd ) );
+
+ /*
+ * Go for comb multiplication, R = M * P
+ */
+ ecp_comb_fixed( k, d, w, &M );
+ MBEDCRYPTO_MPI_CHK( ecp_mul_comb_core( grp, R, T, pre_len, k, d, f_rng, p_rng ) );
+
+ /*
+ * Now get m * P from M * P and normalize it
+ */
+ MBEDCRYPTO_MPI_CHK( ecp_safe_invert_jac( grp, R, ! m_is_odd ) );
+ MBEDCRYPTO_MPI_CHK( ecp_normalize_jac( grp, R ) );
+
+cleanup:
+
+ if( T != NULL && ! p_eq_g )
+ {
+ for( i = 0; i < pre_len; i++ )
+ mbedcrypto_ecp_point_free( &T[i] );
+ mbedcrypto_free( T );
+ }
+
+ mbedcrypto_mpi_free( &M );
+ mbedcrypto_mpi_free( &mm );
+
+ if( ret != 0 )
+ mbedcrypto_ecp_point_free( R );
+
+ return( ret );
+}
+
+#endif /* ECP_SHORTWEIERSTRASS */
+
+#if defined(ECP_MONTGOMERY)
+/*
+ * For Montgomery curves, we do all the internal arithmetic in projective
+ * coordinates. Import/export of points uses only the x coordinates, which is
+ * internaly represented as X / Z.
+ *
+ * For scalar multiplication, we'll use a Montgomery ladder.
+ */
+
+/*
+ * Normalize Montgomery x/z coordinates: X = X/Z, Z = 1
+ * Cost: 1M + 1I
+ */
+static int ecp_normalize_mxz( const mbedcrypto_ecp_group *grp, mbedcrypto_ecp_point *P )
+{
+ int ret;
+
+#if defined(MBEDCRYPTO_ECP_NORMALIZE_MXZ_ALT)
+ if ( mbedcrypto_internal_ecp_grp_capable( grp ) )
+ {
+ return mbedcrypto_internal_ecp_normalize_mxz( grp, P );
+ }
+#endif /* MBEDCRYPTO_ECP_NORMALIZE_MXZ_ALT */
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_inv_mod( &P->Z, &P->Z, &grp->P ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &P->X, &P->X, &P->Z ) ); MOD_MUL( P->X );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_lset( &P->Z, 1 ) );
+
+cleanup:
+ return( ret );
+}
+
+/*
+ * Randomize projective x/z coordinates:
+ * (X, Z) -> (l X, l Z) for random l
+ * This is sort of the reverse operation of ecp_normalize_mxz().
+ *
+ * This countermeasure was first suggested in [2].
+ * Cost: 2M
+ */
+static int ecp_randomize_mxz( const mbedcrypto_ecp_group *grp, mbedcrypto_ecp_point *P,
+ int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
+{
+ int ret;
+ mbedcrypto_mpi l;
+ size_t p_size;
+ int count = 0;
+
+#if defined(MBEDCRYPTO_ECP_RANDOMIZE_MXZ_ALT)
+ if ( mbedcrypto_internal_ecp_grp_capable( grp ) )
+ {
+ return mbedcrypto_internal_ecp_randomize_mxz( grp, P, f_rng, p_rng );
+ }
+#endif /* MBEDCRYPTO_ECP_RANDOMIZE_MXZ_ALT */
+
+ p_size = ( grp->pbits + 7 ) / 8;
+ mbedcrypto_mpi_init( &l );
+
+ /* Generate l such that 1 < l < p */
+ do
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_fill_random( &l, p_size, f_rng, p_rng ) );
+
+ while( mbedcrypto_mpi_cmp_mpi( &l, &grp->P ) >= 0 )
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_r( &l, 1 ) );
+
+ if( count++ > 10 )
+ return( MBEDCRYPTO_ERR_ECP_RANDOM_FAILED );
+ }
+ while( mbedcrypto_mpi_cmp_int( &l, 1 ) <= 0 );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &P->X, &P->X, &l ) ); MOD_MUL( P->X );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &P->Z, &P->Z, &l ) ); MOD_MUL( P->Z );
+
+cleanup:
+ mbedcrypto_mpi_free( &l );
+
+ return( ret );
+}
+
+/*
+ * Double-and-add: R = 2P, S = P + Q, with d = X(P - Q),
+ * for Montgomery curves in x/z coordinates.
+ *
+ * http://www.hyperelliptic.org/EFD/g1p/auto-code/montgom/xz/ladder/mladd-1987-m.op3
+ * with
+ * d = X1
+ * P = (X2, Z2)
+ * Q = (X3, Z3)
+ * R = (X4, Z4)
+ * S = (X5, Z5)
+ * and eliminating temporary variables tO, ..., t4.
+ *
+ * Cost: 5M + 4S
+ */
+static int ecp_double_add_mxz( const mbedcrypto_ecp_group *grp,
+ mbedcrypto_ecp_point *R, mbedcrypto_ecp_point *S,
+ const mbedcrypto_ecp_point *P, const mbedcrypto_ecp_point *Q,
+ const mbedcrypto_mpi *d )
+{
+ int ret;
+ mbedcrypto_mpi A, AA, B, BB, E, C, D, DA, CB;
+
+#if defined(MBEDCRYPTO_ECP_DOUBLE_ADD_MXZ_ALT)
+ if ( mbedcrypto_internal_ecp_grp_capable( grp ) )
+ {
+ return mbedcrypto_internal_ecp_double_add_mxz( grp, R, S, P, Q, d );
+ }
+#endif /* MBEDCRYPTO_ECP_DOUBLE_ADD_MXZ_ALT */
+
+ mbedcrypto_mpi_init( &A ); mbedcrypto_mpi_init( &AA ); mbedcrypto_mpi_init( &B );
+ mbedcrypto_mpi_init( &BB ); mbedcrypto_mpi_init( &E ); mbedcrypto_mpi_init( &C );
+ mbedcrypto_mpi_init( &D ); mbedcrypto_mpi_init( &DA ); mbedcrypto_mpi_init( &CB );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_mpi( &A, &P->X, &P->Z ) ); MOD_ADD( A );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &AA, &A, &A ) ); MOD_MUL( AA );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &B, &P->X, &P->Z ) ); MOD_SUB( B );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &BB, &B, &B ) ); MOD_MUL( BB );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &E, &AA, &BB ) ); MOD_SUB( E );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_mpi( &C, &Q->X, &Q->Z ) ); MOD_ADD( C );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &D, &Q->X, &Q->Z ) ); MOD_SUB( D );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &DA, &D, &A ) ); MOD_MUL( DA );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &CB, &C, &B ) ); MOD_MUL( CB );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_mpi( &S->X, &DA, &CB ) ); MOD_MUL( S->X );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &S->X, &S->X, &S->X ) ); MOD_MUL( S->X );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &S->Z, &DA, &CB ) ); MOD_SUB( S->Z );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &S->Z, &S->Z, &S->Z ) ); MOD_MUL( S->Z );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &S->Z, d, &S->Z ) ); MOD_MUL( S->Z );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &R->X, &AA, &BB ) ); MOD_MUL( R->X );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &R->Z, &grp->A, &E ) ); MOD_MUL( R->Z );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_mpi( &R->Z, &BB, &R->Z ) ); MOD_ADD( R->Z );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &R->Z, &E, &R->Z ) ); MOD_MUL( R->Z );
+
+cleanup:
+ mbedcrypto_mpi_free( &A ); mbedcrypto_mpi_free( &AA ); mbedcrypto_mpi_free( &B );
+ mbedcrypto_mpi_free( &BB ); mbedcrypto_mpi_free( &E ); mbedcrypto_mpi_free( &C );
+ mbedcrypto_mpi_free( &D ); mbedcrypto_mpi_free( &DA ); mbedcrypto_mpi_free( &CB );
+
+ return( ret );
+}
+
+/*
+ * Multiplication with Montgomery ladder in x/z coordinates,
+ * for curves in Montgomery form
+ */
+static int ecp_mul_mxz( mbedcrypto_ecp_group *grp, mbedcrypto_ecp_point *R,
+ const mbedcrypto_mpi *m, const mbedcrypto_ecp_point *P,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng )
+{
+ int ret;
+ size_t i;
+ unsigned char b;
+ mbedcrypto_ecp_point RP;
+ mbedcrypto_mpi PX;
+
+ mbedcrypto_ecp_point_init( &RP ); mbedcrypto_mpi_init( &PX );
+
+ /* Save PX and read from P before writing to R, in case P == R */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &PX, &P->X ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_ecp_copy( &RP, P ) );
+
+ /* Set R to zero in modified x/z coordinates */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_lset( &R->X, 1 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_lset( &R->Z, 0 ) );
+ mbedcrypto_mpi_free( &R->Y );
+
+ /* RP.X might be sligtly larger than P, so reduce it */
+ MOD_ADD( RP.X );
+
+ /* Randomize coordinates of the starting point */
+ if( f_rng != NULL )
+ MBEDCRYPTO_MPI_CHK( ecp_randomize_mxz( grp, &RP, f_rng, p_rng ) );
+
+ /* Loop invariant: R = result so far, RP = R + P */
+ i = mbedcrypto_mpi_bitlen( m ); /* one past the (zero-based) most significant bit */
+ while( i-- > 0 )
+ {
+ b = mbedcrypto_mpi_get_bit( m, i );
+ /*
+ * if (b) R = 2R + P else R = 2R,
+ * which is:
+ * if (b) double_add( RP, R, RP, R )
+ * else double_add( R, RP, R, RP )
+ * but using safe conditional swaps to avoid leaks
+ */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_safe_cond_swap( &R->X, &RP.X, b ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_safe_cond_swap( &R->Z, &RP.Z, b ) );
+ MBEDCRYPTO_MPI_CHK( ecp_double_add_mxz( grp, R, &RP, R, &RP, &PX ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_safe_cond_swap( &R->X, &RP.X, b ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_safe_cond_swap( &R->Z, &RP.Z, b ) );
+ }
+
+ MBEDCRYPTO_MPI_CHK( ecp_normalize_mxz( grp, R ) );
+
+cleanup:
+ mbedcrypto_ecp_point_free( &RP ); mbedcrypto_mpi_free( &PX );
+
+ return( ret );
+}
+
+#endif /* ECP_MONTGOMERY */
+
+/*
+ * Multiplication R = m * P
+ */
+int mbedcrypto_ecp_mul( mbedcrypto_ecp_group *grp, mbedcrypto_ecp_point *R,
+ const mbedcrypto_mpi *m, const mbedcrypto_ecp_point *P,
+ int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
+{
+ int ret = MBEDCRYPTO_ERR_ECP_BAD_INPUT_DATA;
+#if defined(MBEDCRYPTO_ECP_INTERNAL_ALT)
+ char is_grp_capable = 0;
+#endif
+
+ /* Common sanity checks */
+ if( mbedcrypto_mpi_cmp_int( &P->Z, 1 ) != 0 )
+ return( MBEDCRYPTO_ERR_ECP_BAD_INPUT_DATA );
+
+ if( ( ret = mbedcrypto_ecp_check_privkey( grp, m ) ) != 0 ||
+ ( ret = mbedcrypto_ecp_check_pubkey( grp, P ) ) != 0 )
+ return( ret );
+
+#if defined(MBEDCRYPTO_ECP_INTERNAL_ALT)
+ if ( is_grp_capable = mbedcrypto_internal_ecp_grp_capable( grp ) )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_internal_ecp_init( grp ) );
+ }
+
+#endif /* MBEDCRYPTO_ECP_INTERNAL_ALT */
+#if defined(ECP_MONTGOMERY)
+ if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY )
+ ret = ecp_mul_mxz( grp, R, m, P, f_rng, p_rng );
+
+#endif
+#if defined(ECP_SHORTWEIERSTRASS)
+ if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS )
+ ret = ecp_mul_comb( grp, R, m, P, f_rng, p_rng );
+
+#endif
+#if defined(MBEDCRYPTO_ECP_INTERNAL_ALT)
+cleanup:
+
+ if ( is_grp_capable )
+ {
+ mbedcrypto_internal_ecp_free( grp );
+ }
+
+#endif /* MBEDCRYPTO_ECP_INTERNAL_ALT */
+ return( ret );
+}
+
+#if defined(ECP_SHORTWEIERSTRASS)
+/*
+ * Check that an affine point is valid as a public key,
+ * short weierstrass curves (SEC1 3.2.3.1)
+ */
+static int ecp_check_pubkey_sw( const mbedcrypto_ecp_group *grp, const mbedcrypto_ecp_point *pt )
+{
+ int ret;
+ mbedcrypto_mpi YY, RHS;
+
+ /* pt coordinates must be normalized for our checks */
+ if( mbedcrypto_mpi_cmp_int( &pt->X, 0 ) < 0 ||
+ mbedcrypto_mpi_cmp_int( &pt->Y, 0 ) < 0 ||
+ mbedcrypto_mpi_cmp_mpi( &pt->X, &grp->P ) >= 0 ||
+ mbedcrypto_mpi_cmp_mpi( &pt->Y, &grp->P ) >= 0 )
+ return( MBEDCRYPTO_ERR_ECP_INVALID_KEY );
+
+ mbedcrypto_mpi_init( &YY ); mbedcrypto_mpi_init( &RHS );
+
+ /*
+ * YY = Y^2
+ * RHS = X (X^2 + A) + B = X^3 + A X + B
+ */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &YY, &pt->Y, &pt->Y ) ); MOD_MUL( YY );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &RHS, &pt->X, &pt->X ) ); MOD_MUL( RHS );
+
+ /* Special case for A = -3 */
+ if( grp->A.p == NULL )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_int( &RHS, &RHS, 3 ) ); MOD_SUB( RHS );
+ }
+ else
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_mpi( &RHS, &RHS, &grp->A ) ); MOD_ADD( RHS );
+ }
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &RHS, &RHS, &pt->X ) ); MOD_MUL( RHS );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_mpi( &RHS, &RHS, &grp->B ) ); MOD_ADD( RHS );
+
+ if( mbedcrypto_mpi_cmp_mpi( &YY, &RHS ) != 0 )
+ ret = MBEDCRYPTO_ERR_ECP_INVALID_KEY;
+
+cleanup:
+
+ mbedcrypto_mpi_free( &YY ); mbedcrypto_mpi_free( &RHS );
+
+ return( ret );
+}
+#endif /* ECP_SHORTWEIERSTRASS */
+
+/*
+ * R = m * P with shortcuts for m == 1 and m == -1
+ * NOT constant-time - ONLY for short Weierstrass!
+ */
+static int mbedcrypto_ecp_mul_shortcuts( mbedcrypto_ecp_group *grp,
+ mbedcrypto_ecp_point *R,
+ const mbedcrypto_mpi *m,
+ const mbedcrypto_ecp_point *P )
+{
+ int ret;
+
+ if( mbedcrypto_mpi_cmp_int( m, 1 ) == 0 )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_ecp_copy( R, P ) );
+ }
+ else if( mbedcrypto_mpi_cmp_int( m, -1 ) == 0 )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_ecp_copy( R, P ) );
+ if( mbedcrypto_mpi_cmp_int( &R->Y, 0 ) != 0 )
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &R->Y, &grp->P, &R->Y ) );
+ }
+ else
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_ecp_mul( grp, R, m, P, NULL, NULL ) );
+ }
+
+cleanup:
+ return( ret );
+}
+
+/*
+ * Linear combination
+ * NOT constant-time
+ */
+int mbedcrypto_ecp_muladd( mbedcrypto_ecp_group *grp, mbedcrypto_ecp_point *R,
+ const mbedcrypto_mpi *m, const mbedcrypto_ecp_point *P,
+ const mbedcrypto_mpi *n, const mbedcrypto_ecp_point *Q )
+{
+ int ret;
+ mbedcrypto_ecp_point mP;
+#if defined(MBEDCRYPTO_ECP_INTERNAL_ALT)
+ char is_grp_capable = 0;
+#endif
+
+ if( ecp_get_type( grp ) != ECP_TYPE_SHORT_WEIERSTRASS )
+ return( MBEDCRYPTO_ERR_ECP_FEATURE_UNAVAILABLE );
+
+ mbedcrypto_ecp_point_init( &mP );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_ecp_mul_shortcuts( grp, &mP, m, P ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_ecp_mul_shortcuts( grp, R, n, Q ) );
+
+#if defined(MBEDCRYPTO_ECP_INTERNAL_ALT)
+ if ( is_grp_capable = mbedcrypto_internal_ecp_grp_capable( grp ) )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_internal_ecp_init( grp ) );
+ }
+
+#endif /* MBEDCRYPTO_ECP_INTERNAL_ALT */
+ MBEDCRYPTO_MPI_CHK( ecp_add_mixed( grp, R, &mP, R ) );
+ MBEDCRYPTO_MPI_CHK( ecp_normalize_jac( grp, R ) );
+
+cleanup:
+
+#if defined(MBEDCRYPTO_ECP_INTERNAL_ALT)
+ if ( is_grp_capable )
+ {
+ mbedcrypto_internal_ecp_free( grp );
+ }
+
+#endif /* MBEDCRYPTO_ECP_INTERNAL_ALT */
+ mbedcrypto_ecp_point_free( &mP );
+
+ return( ret );
+}
+
+
+#if defined(ECP_MONTGOMERY)
+/*
+ * Check validity of a public key for Montgomery curves with x-only schemes
+ */
+static int ecp_check_pubkey_mx( const mbedcrypto_ecp_group *grp, const mbedcrypto_ecp_point *pt )
+{
+ /* [Curve25519 p. 5] Just check X is the correct number of bytes */
+ /* Allow any public value, if it's too big then we'll just reduce it mod p
+ * (RFC 7748 sec. 5 para. 3). */
+ if( mbedcrypto_mpi_size( &pt->X ) > ( grp->nbits + 7 ) / 8 )
+ return( MBEDCRYPTO_ERR_ECP_INVALID_KEY );
+
+ return( 0 );
+}
+#endif /* ECP_MONTGOMERY */
+
+/*
+ * Check that a point is valid as a public key
+ */
+int mbedcrypto_ecp_check_pubkey( const mbedcrypto_ecp_group *grp, const mbedcrypto_ecp_point *pt )
+{
+ /* Must use affine coordinates */
+ if( mbedcrypto_mpi_cmp_int( &pt->Z, 1 ) != 0 )
+ return( MBEDCRYPTO_ERR_ECP_INVALID_KEY );
+
+#if defined(ECP_MONTGOMERY)
+ if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY )
+ return( ecp_check_pubkey_mx( grp, pt ) );
+#endif
+#if defined(ECP_SHORTWEIERSTRASS)
+ if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS )
+ return( ecp_check_pubkey_sw( grp, pt ) );
+#endif
+ return( MBEDCRYPTO_ERR_ECP_BAD_INPUT_DATA );
+}
+
+/*
+ * Check that an mbedcrypto_mpi is valid as a private key
+ */
+int mbedcrypto_ecp_check_privkey( const mbedcrypto_ecp_group *grp, const mbedcrypto_mpi *d )
+{
+#if defined(ECP_MONTGOMERY)
+ if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY )
+ {
+ /* see RFC 7748 sec. 5 para. 5 */
+ if( mbedcrypto_mpi_get_bit( d, 0 ) != 0 ||
+ mbedcrypto_mpi_get_bit( d, 1 ) != 0 ||
+ mbedcrypto_mpi_bitlen( d ) - 1 != grp->nbits ) /* mbedcrypto_mpi_bitlen is one-based! */
+ return( MBEDCRYPTO_ERR_ECP_INVALID_KEY );
+ else
+
+ /* see [Curve25519] page 5 */
+ if( grp->nbits == 254 && mbedcrypto_mpi_get_bit( d, 2 ) != 0 )
+ return( MBEDCRYPTO_ERR_ECP_INVALID_KEY );
+
+ return( 0 );
+ }
+#endif /* ECP_MONTGOMERY */
+#if defined(ECP_SHORTWEIERSTRASS)
+ if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS )
+ {
+ /* see SEC1 3.2 */
+ if( mbedcrypto_mpi_cmp_int( d, 1 ) < 0 ||
+ mbedcrypto_mpi_cmp_mpi( d, &grp->N ) >= 0 )
+ return( MBEDCRYPTO_ERR_ECP_INVALID_KEY );
+ else
+ return( 0 );
+ }
+#endif /* ECP_SHORTWEIERSTRASS */
+
+ return( MBEDCRYPTO_ERR_ECP_BAD_INPUT_DATA );
+}
+
+/*
+ * Generate a keypair with configurable base point
+ */
+int mbedcrypto_ecp_gen_keypair_base( mbedcrypto_ecp_group *grp,
+ const mbedcrypto_ecp_point *G,
+ mbedcrypto_mpi *d, mbedcrypto_ecp_point *Q,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng )
+{
+ int ret;
+ size_t n_size = ( grp->nbits + 7 ) / 8;
+
+#if defined(ECP_MONTGOMERY)
+ if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY )
+ {
+ /* [M225] page 5 */
+ size_t b;
+
+ do {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_fill_random( d, n_size, f_rng, p_rng ) );
+ } while( mbedcrypto_mpi_bitlen( d ) == 0);
+
+ /* Make sure the most significant bit is nbits */
+ b = mbedcrypto_mpi_bitlen( d ) - 1; /* mbedcrypto_mpi_bitlen is one-based */
+ if( b > grp->nbits )
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_r( d, b - grp->nbits ) );
+ else
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_set_bit( d, grp->nbits, 1 ) );
+
+ /* Make sure the last two bits are unset for Curve448, three bits for
+ Curve25519 */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_set_bit( d, 0, 0 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_set_bit( d, 1, 0 ) );
+ if( grp->nbits == 254 )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_set_bit( d, 2, 0 ) );
+ }
+ }
+ else
+#endif /* ECP_MONTGOMERY */
+#if defined(ECP_SHORTWEIERSTRASS)
+ if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS )
+ {
+ /* SEC1 3.2.1: Generate d such that 1 <= n < N */
+ int count = 0;
+
+ /*
+ * Match the procedure given in RFC 6979 (deterministic ECDSA):
+ * - use the same byte ordering;
+ * - keep the leftmost nbits bits of the generated octet string;
+ * - try until result is in the desired range.
+ * This also avoids any biais, which is especially important for ECDSA.
+ */
+ do
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_fill_random( d, n_size, f_rng, p_rng ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_r( d, 8 * n_size - grp->nbits ) );
+
+ /*
+ * Each try has at worst a probability 1/2 of failing (the msb has
+ * a probability 1/2 of being 0, and then the result will be < N),
+ * so after 30 tries failure probability is a most 2**(-30).
+ *
+ * For most curves, 1 try is enough with overwhelming probability,
+ * since N starts with a lot of 1s in binary, but some curves
+ * such as secp224k1 are actually very close to the worst case.
+ */
+ if( ++count > 30 )
+ return( MBEDCRYPTO_ERR_ECP_RANDOM_FAILED );
+ }
+ while( mbedcrypto_mpi_cmp_int( d, 1 ) < 0 ||
+ mbedcrypto_mpi_cmp_mpi( d, &grp->N ) >= 0 );
+ }
+ else
+#endif /* ECP_SHORTWEIERSTRASS */
+ return( MBEDCRYPTO_ERR_ECP_BAD_INPUT_DATA );
+
+cleanup:
+ if( ret != 0 )
+ return( ret );
+
+ return( mbedcrypto_ecp_mul( grp, Q, d, G, f_rng, p_rng ) );
+}
+
+/*
+ * Generate key pair, wrapper for conventional base point
+ */
+int mbedcrypto_ecp_gen_keypair( mbedcrypto_ecp_group *grp,
+ mbedcrypto_mpi *d, mbedcrypto_ecp_point *Q,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng )
+{
+ return( mbedcrypto_ecp_gen_keypair_base( grp, &grp->G, d, Q, f_rng, p_rng ) );
+}
+
+/*
+ * Generate a keypair, prettier wrapper
+ */
+int mbedcrypto_ecp_gen_key( mbedcrypto_ecp_group_id grp_id, mbedcrypto_ecp_keypair *key,
+ int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
+{
+ int ret;
+
+ if( ( ret = mbedcrypto_ecp_group_load( &key->grp, grp_id ) ) != 0 )
+ return( ret );
+
+ return( mbedcrypto_ecp_gen_keypair( &key->grp, &key->d, &key->Q, f_rng, p_rng ) );
+}
+
+/*
+ * Check a public-private key pair
+ */
+int mbedcrypto_ecp_check_pub_priv( const mbedcrypto_ecp_keypair *pub, const mbedcrypto_ecp_keypair *prv )
+{
+ int ret;
+ mbedcrypto_ecp_point Q;
+ mbedcrypto_ecp_group grp;
+
+ if( pub->grp.id == MBEDCRYPTO_ECP_DP_NONE ||
+ pub->grp.id != prv->grp.id ||
+ mbedcrypto_mpi_cmp_mpi( &pub->Q.X, &prv->Q.X ) ||
+ mbedcrypto_mpi_cmp_mpi( &pub->Q.Y, &prv->Q.Y ) ||
+ mbedcrypto_mpi_cmp_mpi( &pub->Q.Z, &prv->Q.Z ) )
+ {
+ return( MBEDCRYPTO_ERR_ECP_BAD_INPUT_DATA );
+ }
+
+ mbedcrypto_ecp_point_init( &Q );
+ mbedcrypto_ecp_group_init( &grp );
+
+ /* mbedcrypto_ecp_mul() needs a non-const group... */
+ mbedcrypto_ecp_group_copy( &grp, &prv->grp );
+
+ /* Also checks d is valid */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_ecp_mul( &grp, &Q, &prv->d, &prv->grp.G, NULL, NULL ) );
+
+ if( mbedcrypto_mpi_cmp_mpi( &Q.X, &prv->Q.X ) ||
+ mbedcrypto_mpi_cmp_mpi( &Q.Y, &prv->Q.Y ) ||
+ mbedcrypto_mpi_cmp_mpi( &Q.Z, &prv->Q.Z ) )
+ {
+ ret = MBEDCRYPTO_ERR_ECP_BAD_INPUT_DATA;
+ goto cleanup;
+ }
+
+cleanup:
+ mbedcrypto_ecp_point_free( &Q );
+ mbedcrypto_ecp_group_free( &grp );
+
+ return( ret );
+}
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+
+/*
+ * Checkup routine
+ */
+int mbedcrypto_ecp_self_test( int verbose )
+{
+ int ret;
+ size_t i;
+ mbedcrypto_ecp_group grp;
+ mbedcrypto_ecp_point R, P;
+ mbedcrypto_mpi m;
+ unsigned long add_c_prev, dbl_c_prev, mul_c_prev;
+ /* exponents especially adapted for secp192r1 */
+ const char *exponents[] =
+ {
+ "000000000000000000000000000000000000000000000001", /* one */
+ "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22830", /* N - 1 */
+ "5EA6F389A38B8BC81E767753B15AA5569E1782E30ABE7D25", /* random */
+ "400000000000000000000000000000000000000000000000", /* one and zeros */
+ "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", /* all ones */
+ "555555555555555555555555555555555555555555555555", /* 101010... */
+ };
+
+ mbedcrypto_ecp_group_init( &grp );
+ mbedcrypto_ecp_point_init( &R );
+ mbedcrypto_ecp_point_init( &P );
+ mbedcrypto_mpi_init( &m );
+
+ /* Use secp192r1 if available, or any available curve */
+#if defined(MBEDCRYPTO_ECP_DP_SECP192R1_ENABLED)
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_ecp_group_load( &grp, MBEDCRYPTO_ECP_DP_SECP192R1 ) );
+#else
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_ecp_group_load( &grp, mbedcrypto_ecp_curve_list()->grp_id ) );
+#endif
+
+ if( verbose != 0 )
+ mbedcrypto_printf( " ECP test #1 (constant op_count, base point G): " );
+
+ /* Do a dummy multiplication first to trigger precomputation */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_lset( &m, 2 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_ecp_mul( &grp, &P, &m, &grp.G, NULL, NULL ) );
+
+ add_count = 0;
+ dbl_count = 0;
+ mul_count = 0;
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_string( &m, 16, exponents[0] ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_ecp_mul( &grp, &R, &m, &grp.G, NULL, NULL ) );
+
+ for( i = 1; i < sizeof( exponents ) / sizeof( exponents[0] ); i++ )
+ {
+ add_c_prev = add_count;
+ dbl_c_prev = dbl_count;
+ mul_c_prev = mul_count;
+ add_count = 0;
+ dbl_count = 0;
+ mul_count = 0;
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_string( &m, 16, exponents[i] ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_ecp_mul( &grp, &R, &m, &grp.G, NULL, NULL ) );
+
+ if( add_count != add_c_prev ||
+ dbl_count != dbl_c_prev ||
+ mul_count != mul_c_prev )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed (%u)\n", (unsigned int) i );
+
+ ret = 1;
+ goto cleanup;
+ }
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+
+ if( verbose != 0 )
+ mbedcrypto_printf( " ECP test #2 (constant op_count, other point): " );
+ /* We computed P = 2G last time, use it */
+
+ add_count = 0;
+ dbl_count = 0;
+ mul_count = 0;
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_string( &m, 16, exponents[0] ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_ecp_mul( &grp, &R, &m, &P, NULL, NULL ) );
+
+ for( i = 1; i < sizeof( exponents ) / sizeof( exponents[0] ); i++ )
+ {
+ add_c_prev = add_count;
+ dbl_c_prev = dbl_count;
+ mul_c_prev = mul_count;
+ add_count = 0;
+ dbl_count = 0;
+ mul_count = 0;
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_string( &m, 16, exponents[i] ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_ecp_mul( &grp, &R, &m, &P, NULL, NULL ) );
+
+ if( add_count != add_c_prev ||
+ dbl_count != dbl_c_prev ||
+ mul_count != mul_c_prev )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed (%u)\n", (unsigned int) i );
+
+ ret = 1;
+ goto cleanup;
+ }
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+
+cleanup:
+
+ if( ret < 0 && verbose != 0 )
+ mbedcrypto_printf( "Unexpected error, return code = %08X\n", ret );
+
+ mbedcrypto_ecp_group_free( &grp );
+ mbedcrypto_ecp_point_free( &R );
+ mbedcrypto_ecp_point_free( &P );
+ mbedcrypto_mpi_free( &m );
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "\n" );
+
+ return( ret );
+}
+
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#endif /* !MBEDCRYPTO_ECP_ALT */
+
+#endif /* MBEDCRYPTO_ECP_C */
diff --git a/library/ecp_curves.c b/library/ecp_curves.c
new file mode 100644
index 0000000..70157b2
--- /dev/null
+++ b/library/ecp_curves.c
@@ -0,0 +1,1460 @@
+/*
+ * Elliptic curves over GF(p): curve-specific data and 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 Crypto (https://tls.mbed.org)
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_ECP_C)
+
+#include "mbedcrypto/ecp.h"
+
+#include <string.h>
+
+#if !defined(MBEDCRYPTO_ECP_ALT)
+
+#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
+ !defined(inline) && !defined(__cplusplus)
+#define inline __inline
+#endif
+
+/*
+ * Conversion macros for embedded constants:
+ * build lists of mbedcrypto_mpi_uint's from lists of unsigned char's grouped by 8, 4 or 2
+ */
+#if defined(MBEDCRYPTO_HAVE_INT32)
+
+#define BYTES_TO_T_UINT_4( a, b, c, d ) \
+ ( (mbedcrypto_mpi_uint) a << 0 ) | \
+ ( (mbedcrypto_mpi_uint) b << 8 ) | \
+ ( (mbedcrypto_mpi_uint) c << 16 ) | \
+ ( (mbedcrypto_mpi_uint) d << 24 )
+
+#define BYTES_TO_T_UINT_2( a, b ) \
+ BYTES_TO_T_UINT_4( a, b, 0, 0 )
+
+#define BYTES_TO_T_UINT_8( a, b, c, d, e, f, g, h ) \
+ BYTES_TO_T_UINT_4( a, b, c, d ), \
+ BYTES_TO_T_UINT_4( e, f, g, h )
+
+#else /* 64-bits */
+
+#define BYTES_TO_T_UINT_8( a, b, c, d, e, f, g, h ) \
+ ( (mbedcrypto_mpi_uint) a << 0 ) | \
+ ( (mbedcrypto_mpi_uint) b << 8 ) | \
+ ( (mbedcrypto_mpi_uint) c << 16 ) | \
+ ( (mbedcrypto_mpi_uint) d << 24 ) | \
+ ( (mbedcrypto_mpi_uint) e << 32 ) | \
+ ( (mbedcrypto_mpi_uint) f << 40 ) | \
+ ( (mbedcrypto_mpi_uint) g << 48 ) | \
+ ( (mbedcrypto_mpi_uint) h << 56 )
+
+#define BYTES_TO_T_UINT_4( a, b, c, d ) \
+ BYTES_TO_T_UINT_8( a, b, c, d, 0, 0, 0, 0 )
+
+#define BYTES_TO_T_UINT_2( a, b ) \
+ BYTES_TO_T_UINT_8( a, b, 0, 0, 0, 0, 0, 0 )
+
+#endif /* bits in mbedcrypto_mpi_uint */
+
+/*
+ * Note: the constants are in little-endian order
+ * to be directly usable in MPIs
+ */
+
+/*
+ * Domain parameters for secp192r1
+ */
+#if defined(MBEDCRYPTO_ECP_DP_SECP192R1_ENABLED)
+static const mbedcrypto_mpi_uint secp192r1_p[] = {
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+};
+static const mbedcrypto_mpi_uint secp192r1_b[] = {
+ BYTES_TO_T_UINT_8( 0xB1, 0xB9, 0x46, 0xC1, 0xEC, 0xDE, 0xB8, 0xFE ),
+ BYTES_TO_T_UINT_8( 0x49, 0x30, 0x24, 0x72, 0xAB, 0xE9, 0xA7, 0x0F ),
+ BYTES_TO_T_UINT_8( 0xE7, 0x80, 0x9C, 0xE5, 0x19, 0x05, 0x21, 0x64 ),
+};
+static const mbedcrypto_mpi_uint secp192r1_gx[] = {
+ BYTES_TO_T_UINT_8( 0x12, 0x10, 0xFF, 0x82, 0xFD, 0x0A, 0xFF, 0xF4 ),
+ BYTES_TO_T_UINT_8( 0x00, 0x88, 0xA1, 0x43, 0xEB, 0x20, 0xBF, 0x7C ),
+ BYTES_TO_T_UINT_8( 0xF6, 0x90, 0x30, 0xB0, 0x0E, 0xA8, 0x8D, 0x18 ),
+};
+static const mbedcrypto_mpi_uint secp192r1_gy[] = {
+ BYTES_TO_T_UINT_8( 0x11, 0x48, 0x79, 0x1E, 0xA1, 0x77, 0xF9, 0x73 ),
+ BYTES_TO_T_UINT_8( 0xD5, 0xCD, 0x24, 0x6B, 0xED, 0x11, 0x10, 0x63 ),
+ BYTES_TO_T_UINT_8( 0x78, 0xDA, 0xC8, 0xFF, 0x95, 0x2B, 0x19, 0x07 ),
+};
+static const mbedcrypto_mpi_uint secp192r1_n[] = {
+ BYTES_TO_T_UINT_8( 0x31, 0x28, 0xD2, 0xB4, 0xB1, 0xC9, 0x6B, 0x14 ),
+ BYTES_TO_T_UINT_8( 0x36, 0xF8, 0xDE, 0x99, 0xFF, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+};
+#endif /* MBEDCRYPTO_ECP_DP_SECP192R1_ENABLED */
+
+/*
+ * Domain parameters for secp224r1
+ */
+#if defined(MBEDCRYPTO_ECP_DP_SECP224R1_ENABLED)
+static const mbedcrypto_mpi_uint secp224r1_p[] = {
+ BYTES_TO_T_UINT_8( 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ),
+ BYTES_TO_T_UINT_8( 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 ),
+};
+static const mbedcrypto_mpi_uint secp224r1_b[] = {
+ BYTES_TO_T_UINT_8( 0xB4, 0xFF, 0x55, 0x23, 0x43, 0x39, 0x0B, 0x27 ),
+ BYTES_TO_T_UINT_8( 0xBA, 0xD8, 0xBF, 0xD7, 0xB7, 0xB0, 0x44, 0x50 ),
+ BYTES_TO_T_UINT_8( 0x56, 0x32, 0x41, 0xF5, 0xAB, 0xB3, 0x04, 0x0C ),
+ BYTES_TO_T_UINT_4( 0x85, 0x0A, 0x05, 0xB4 ),
+};
+static const mbedcrypto_mpi_uint secp224r1_gx[] = {
+ BYTES_TO_T_UINT_8( 0x21, 0x1D, 0x5C, 0x11, 0xD6, 0x80, 0x32, 0x34 ),
+ BYTES_TO_T_UINT_8( 0x22, 0x11, 0xC2, 0x56, 0xD3, 0xC1, 0x03, 0x4A ),
+ BYTES_TO_T_UINT_8( 0xB9, 0x90, 0x13, 0x32, 0x7F, 0xBF, 0xB4, 0x6B ),
+ BYTES_TO_T_UINT_4( 0xBD, 0x0C, 0x0E, 0xB7 ),
+};
+static const mbedcrypto_mpi_uint secp224r1_gy[] = {
+ BYTES_TO_T_UINT_8( 0x34, 0x7E, 0x00, 0x85, 0x99, 0x81, 0xD5, 0x44 ),
+ BYTES_TO_T_UINT_8( 0x64, 0x47, 0x07, 0x5A, 0xA0, 0x75, 0x43, 0xCD ),
+ BYTES_TO_T_UINT_8( 0xE6, 0xDF, 0x22, 0x4C, 0xFB, 0x23, 0xF7, 0xB5 ),
+ BYTES_TO_T_UINT_4( 0x88, 0x63, 0x37, 0xBD ),
+};
+static const mbedcrypto_mpi_uint secp224r1_n[] = {
+ BYTES_TO_T_UINT_8( 0x3D, 0x2A, 0x5C, 0x5C, 0x45, 0x29, 0xDD, 0x13 ),
+ BYTES_TO_T_UINT_8( 0x3E, 0xF0, 0xB8, 0xE0, 0xA2, 0x16, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_4( 0xFF, 0xFF, 0xFF, 0xFF ),
+};
+#endif /* MBEDCRYPTO_ECP_DP_SECP224R1_ENABLED */
+
+/*
+ * Domain parameters for secp256r1
+ */
+#if defined(MBEDCRYPTO_ECP_DP_SECP256R1_ENABLED)
+static const mbedcrypto_mpi_uint secp256r1_p[] = {
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 ),
+ BYTES_TO_T_UINT_8( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ),
+ BYTES_TO_T_UINT_8( 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF ),
+};
+static const mbedcrypto_mpi_uint secp256r1_b[] = {
+ BYTES_TO_T_UINT_8( 0x4B, 0x60, 0xD2, 0x27, 0x3E, 0x3C, 0xCE, 0x3B ),
+ BYTES_TO_T_UINT_8( 0xF6, 0xB0, 0x53, 0xCC, 0xB0, 0x06, 0x1D, 0x65 ),
+ BYTES_TO_T_UINT_8( 0xBC, 0x86, 0x98, 0x76, 0x55, 0xBD, 0xEB, 0xB3 ),
+ BYTES_TO_T_UINT_8( 0xE7, 0x93, 0x3A, 0xAA, 0xD8, 0x35, 0xC6, 0x5A ),
+};
+static const mbedcrypto_mpi_uint secp256r1_gx[] = {
+ BYTES_TO_T_UINT_8( 0x96, 0xC2, 0x98, 0xD8, 0x45, 0x39, 0xA1, 0xF4 ),
+ BYTES_TO_T_UINT_8( 0xA0, 0x33, 0xEB, 0x2D, 0x81, 0x7D, 0x03, 0x77 ),
+ BYTES_TO_T_UINT_8( 0xF2, 0x40, 0xA4, 0x63, 0xE5, 0xE6, 0xBC, 0xF8 ),
+ BYTES_TO_T_UINT_8( 0x47, 0x42, 0x2C, 0xE1, 0xF2, 0xD1, 0x17, 0x6B ),
+};
+static const mbedcrypto_mpi_uint secp256r1_gy[] = {
+ BYTES_TO_T_UINT_8( 0xF5, 0x51, 0xBF, 0x37, 0x68, 0x40, 0xB6, 0xCB ),
+ BYTES_TO_T_UINT_8( 0xCE, 0x5E, 0x31, 0x6B, 0x57, 0x33, 0xCE, 0x2B ),
+ BYTES_TO_T_UINT_8( 0x16, 0x9E, 0x0F, 0x7C, 0x4A, 0xEB, 0xE7, 0x8E ),
+ BYTES_TO_T_UINT_8( 0x9B, 0x7F, 0x1A, 0xFE, 0xE2, 0x42, 0xE3, 0x4F ),
+};
+static const mbedcrypto_mpi_uint secp256r1_n[] = {
+ BYTES_TO_T_UINT_8( 0x51, 0x25, 0x63, 0xFC, 0xC2, 0xCA, 0xB9, 0xF3 ),
+ BYTES_TO_T_UINT_8( 0x84, 0x9E, 0x17, 0xA7, 0xAD, 0xFA, 0xE6, 0xBC ),
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF ),
+};
+#endif /* MBEDCRYPTO_ECP_DP_SECP256R1_ENABLED */
+
+/*
+ * Domain parameters for secp384r1
+ */
+#if defined(MBEDCRYPTO_ECP_DP_SECP384R1_ENABLED)
+static const mbedcrypto_mpi_uint secp384r1_p[] = {
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 ),
+ BYTES_TO_T_UINT_8( 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+};
+static const mbedcrypto_mpi_uint secp384r1_b[] = {
+ BYTES_TO_T_UINT_8( 0xEF, 0x2A, 0xEC, 0xD3, 0xED, 0xC8, 0x85, 0x2A ),
+ BYTES_TO_T_UINT_8( 0x9D, 0xD1, 0x2E, 0x8A, 0x8D, 0x39, 0x56, 0xC6 ),
+ BYTES_TO_T_UINT_8( 0x5A, 0x87, 0x13, 0x50, 0x8F, 0x08, 0x14, 0x03 ),
+ BYTES_TO_T_UINT_8( 0x12, 0x41, 0x81, 0xFE, 0x6E, 0x9C, 0x1D, 0x18 ),
+ BYTES_TO_T_UINT_8( 0x19, 0x2D, 0xF8, 0xE3, 0x6B, 0x05, 0x8E, 0x98 ),
+ BYTES_TO_T_UINT_8( 0xE4, 0xE7, 0x3E, 0xE2, 0xA7, 0x2F, 0x31, 0xB3 ),
+};
+static const mbedcrypto_mpi_uint secp384r1_gx[] = {
+ BYTES_TO_T_UINT_8( 0xB7, 0x0A, 0x76, 0x72, 0x38, 0x5E, 0x54, 0x3A ),
+ BYTES_TO_T_UINT_8( 0x6C, 0x29, 0x55, 0xBF, 0x5D, 0xF2, 0x02, 0x55 ),
+ BYTES_TO_T_UINT_8( 0x38, 0x2A, 0x54, 0x82, 0xE0, 0x41, 0xF7, 0x59 ),
+ BYTES_TO_T_UINT_8( 0x98, 0x9B, 0xA7, 0x8B, 0x62, 0x3B, 0x1D, 0x6E ),
+ BYTES_TO_T_UINT_8( 0x74, 0xAD, 0x20, 0xF3, 0x1E, 0xC7, 0xB1, 0x8E ),
+ BYTES_TO_T_UINT_8( 0x37, 0x05, 0x8B, 0xBE, 0x22, 0xCA, 0x87, 0xAA ),
+};
+static const mbedcrypto_mpi_uint secp384r1_gy[] = {
+ BYTES_TO_T_UINT_8( 0x5F, 0x0E, 0xEA, 0x90, 0x7C, 0x1D, 0x43, 0x7A ),
+ BYTES_TO_T_UINT_8( 0x9D, 0x81, 0x7E, 0x1D, 0xCE, 0xB1, 0x60, 0x0A ),
+ BYTES_TO_T_UINT_8( 0xC0, 0xB8, 0xF0, 0xB5, 0x13, 0x31, 0xDA, 0xE9 ),
+ BYTES_TO_T_UINT_8( 0x7C, 0x14, 0x9A, 0x28, 0xBD, 0x1D, 0xF4, 0xF8 ),
+ BYTES_TO_T_UINT_8( 0x29, 0xDC, 0x92, 0x92, 0xBF, 0x98, 0x9E, 0x5D ),
+ BYTES_TO_T_UINT_8( 0x6F, 0x2C, 0x26, 0x96, 0x4A, 0xDE, 0x17, 0x36 ),
+};
+static const mbedcrypto_mpi_uint secp384r1_n[] = {
+ BYTES_TO_T_UINT_8( 0x73, 0x29, 0xC5, 0xCC, 0x6A, 0x19, 0xEC, 0xEC ),
+ BYTES_TO_T_UINT_8( 0x7A, 0xA7, 0xB0, 0x48, 0xB2, 0x0D, 0x1A, 0x58 ),
+ BYTES_TO_T_UINT_8( 0xDF, 0x2D, 0x37, 0xF4, 0x81, 0x4D, 0x63, 0xC7 ),
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+};
+#endif /* MBEDCRYPTO_ECP_DP_SECP384R1_ENABLED */
+
+/*
+ * Domain parameters for secp521r1
+ */
+#if defined(MBEDCRYPTO_ECP_DP_SECP521R1_ENABLED)
+static const mbedcrypto_mpi_uint secp521r1_p[] = {
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_2( 0xFF, 0x01 ),
+};
+static const mbedcrypto_mpi_uint secp521r1_b[] = {
+ BYTES_TO_T_UINT_8( 0x00, 0x3F, 0x50, 0x6B, 0xD4, 0x1F, 0x45, 0xEF ),
+ BYTES_TO_T_UINT_8( 0xF1, 0x34, 0x2C, 0x3D, 0x88, 0xDF, 0x73, 0x35 ),
+ BYTES_TO_T_UINT_8( 0x07, 0xBF, 0xB1, 0x3B, 0xBD, 0xC0, 0x52, 0x16 ),
+ BYTES_TO_T_UINT_8( 0x7B, 0x93, 0x7E, 0xEC, 0x51, 0x39, 0x19, 0x56 ),
+ BYTES_TO_T_UINT_8( 0xE1, 0x09, 0xF1, 0x8E, 0x91, 0x89, 0xB4, 0xB8 ),
+ BYTES_TO_T_UINT_8( 0xF3, 0x15, 0xB3, 0x99, 0x5B, 0x72, 0xDA, 0xA2 ),
+ BYTES_TO_T_UINT_8( 0xEE, 0x40, 0x85, 0xB6, 0xA0, 0x21, 0x9A, 0x92 ),
+ BYTES_TO_T_UINT_8( 0x1F, 0x9A, 0x1C, 0x8E, 0x61, 0xB9, 0x3E, 0x95 ),
+ BYTES_TO_T_UINT_2( 0x51, 0x00 ),
+};
+static const mbedcrypto_mpi_uint secp521r1_gx[] = {
+ BYTES_TO_T_UINT_8( 0x66, 0xBD, 0xE5, 0xC2, 0x31, 0x7E, 0x7E, 0xF9 ),
+ BYTES_TO_T_UINT_8( 0x9B, 0x42, 0x6A, 0x85, 0xC1, 0xB3, 0x48, 0x33 ),
+ BYTES_TO_T_UINT_8( 0xDE, 0xA8, 0xFF, 0xA2, 0x27, 0xC1, 0x1D, 0xFE ),
+ BYTES_TO_T_UINT_8( 0x28, 0x59, 0xE7, 0xEF, 0x77, 0x5E, 0x4B, 0xA1 ),
+ BYTES_TO_T_UINT_8( 0xBA, 0x3D, 0x4D, 0x6B, 0x60, 0xAF, 0x28, 0xF8 ),
+ BYTES_TO_T_UINT_8( 0x21, 0xB5, 0x3F, 0x05, 0x39, 0x81, 0x64, 0x9C ),
+ BYTES_TO_T_UINT_8( 0x42, 0xB4, 0x95, 0x23, 0x66, 0xCB, 0x3E, 0x9E ),
+ BYTES_TO_T_UINT_8( 0xCD, 0xE9, 0x04, 0x04, 0xB7, 0x06, 0x8E, 0x85 ),
+ BYTES_TO_T_UINT_2( 0xC6, 0x00 ),
+};
+static const mbedcrypto_mpi_uint secp521r1_gy[] = {
+ BYTES_TO_T_UINT_8( 0x50, 0x66, 0xD1, 0x9F, 0x76, 0x94, 0xBE, 0x88 ),
+ BYTES_TO_T_UINT_8( 0x40, 0xC2, 0x72, 0xA2, 0x86, 0x70, 0x3C, 0x35 ),
+ BYTES_TO_T_UINT_8( 0x61, 0x07, 0xAD, 0x3F, 0x01, 0xB9, 0x50, 0xC5 ),
+ BYTES_TO_T_UINT_8( 0x40, 0x26, 0xF4, 0x5E, 0x99, 0x72, 0xEE, 0x97 ),
+ BYTES_TO_T_UINT_8( 0x2C, 0x66, 0x3E, 0x27, 0x17, 0xBD, 0xAF, 0x17 ),
+ BYTES_TO_T_UINT_8( 0x68, 0x44, 0x9B, 0x57, 0x49, 0x44, 0xF5, 0x98 ),
+ BYTES_TO_T_UINT_8( 0xD9, 0x1B, 0x7D, 0x2C, 0xB4, 0x5F, 0x8A, 0x5C ),
+ BYTES_TO_T_UINT_8( 0x04, 0xC0, 0x3B, 0x9A, 0x78, 0x6A, 0x29, 0x39 ),
+ BYTES_TO_T_UINT_2( 0x18, 0x01 ),
+};
+static const mbedcrypto_mpi_uint secp521r1_n[] = {
+ BYTES_TO_T_UINT_8( 0x09, 0x64, 0x38, 0x91, 0x1E, 0xB7, 0x6F, 0xBB ),
+ BYTES_TO_T_UINT_8( 0xAE, 0x47, 0x9C, 0x89, 0xB8, 0xC9, 0xB5, 0x3B ),
+ BYTES_TO_T_UINT_8( 0xD0, 0xA5, 0x09, 0xF7, 0x48, 0x01, 0xCC, 0x7F ),
+ BYTES_TO_T_UINT_8( 0x6B, 0x96, 0x2F, 0xBF, 0x83, 0x87, 0x86, 0x51 ),
+ BYTES_TO_T_UINT_8( 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_2( 0xFF, 0x01 ),
+};
+#endif /* MBEDCRYPTO_ECP_DP_SECP521R1_ENABLED */
+
+#if defined(MBEDCRYPTO_ECP_DP_SECP192K1_ENABLED)
+static const mbedcrypto_mpi_uint secp192k1_p[] = {
+ BYTES_TO_T_UINT_8( 0x37, 0xEE, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+};
+static const mbedcrypto_mpi_uint secp192k1_a[] = {
+ BYTES_TO_T_UINT_2( 0x00, 0x00 ),
+};
+static const mbedcrypto_mpi_uint secp192k1_b[] = {
+ BYTES_TO_T_UINT_2( 0x03, 0x00 ),
+};
+static const mbedcrypto_mpi_uint secp192k1_gx[] = {
+ BYTES_TO_T_UINT_8( 0x7D, 0x6C, 0xE0, 0xEA, 0xB1, 0xD1, 0xA5, 0x1D ),
+ BYTES_TO_T_UINT_8( 0x34, 0xF4, 0xB7, 0x80, 0x02, 0x7D, 0xB0, 0x26 ),
+ BYTES_TO_T_UINT_8( 0xAE, 0xE9, 0x57, 0xC0, 0x0E, 0xF1, 0x4F, 0xDB ),
+};
+static const mbedcrypto_mpi_uint secp192k1_gy[] = {
+ BYTES_TO_T_UINT_8( 0x9D, 0x2F, 0x5E, 0xD9, 0x88, 0xAA, 0x82, 0x40 ),
+ BYTES_TO_T_UINT_8( 0x34, 0x86, 0xBE, 0x15, 0xD0, 0x63, 0x41, 0x84 ),
+ BYTES_TO_T_UINT_8( 0xA7, 0x28, 0x56, 0x9C, 0x6D, 0x2F, 0x2F, 0x9B ),
+};
+static const mbedcrypto_mpi_uint secp192k1_n[] = {
+ BYTES_TO_T_UINT_8( 0x8D, 0xFD, 0xDE, 0x74, 0x6A, 0x46, 0x69, 0x0F ),
+ BYTES_TO_T_UINT_8( 0x17, 0xFC, 0xF2, 0x26, 0xFE, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+};
+#endif /* MBEDCRYPTO_ECP_DP_SECP192K1_ENABLED */
+
+#if defined(MBEDCRYPTO_ECP_DP_SECP224K1_ENABLED)
+static const mbedcrypto_mpi_uint secp224k1_p[] = {
+ BYTES_TO_T_UINT_8( 0x6D, 0xE5, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_4( 0xFF, 0xFF, 0xFF, 0xFF ),
+};
+static const mbedcrypto_mpi_uint secp224k1_a[] = {
+ BYTES_TO_T_UINT_2( 0x00, 0x00 ),
+};
+static const mbedcrypto_mpi_uint secp224k1_b[] = {
+ BYTES_TO_T_UINT_2( 0x05, 0x00 ),
+};
+static const mbedcrypto_mpi_uint secp224k1_gx[] = {
+ BYTES_TO_T_UINT_8( 0x5C, 0xA4, 0xB7, 0xB6, 0x0E, 0x65, 0x7E, 0x0F ),
+ BYTES_TO_T_UINT_8( 0xA9, 0x75, 0x70, 0xE4, 0xE9, 0x67, 0xA4, 0x69 ),
+ BYTES_TO_T_UINT_8( 0xA1, 0x28, 0xFC, 0x30, 0xDF, 0x99, 0xF0, 0x4D ),
+ BYTES_TO_T_UINT_4( 0x33, 0x5B, 0x45, 0xA1 ),
+};
+static const mbedcrypto_mpi_uint secp224k1_gy[] = {
+ BYTES_TO_T_UINT_8( 0xA5, 0x61, 0x6D, 0x55, 0xDB, 0x4B, 0xCA, 0xE2 ),
+ BYTES_TO_T_UINT_8( 0x59, 0xBD, 0xB0, 0xC0, 0xF7, 0x19, 0xE3, 0xF7 ),
+ BYTES_TO_T_UINT_8( 0xD6, 0xFB, 0xCA, 0x82, 0x42, 0x34, 0xBA, 0x7F ),
+ BYTES_TO_T_UINT_4( 0xED, 0x9F, 0x08, 0x7E ),
+};
+static const mbedcrypto_mpi_uint secp224k1_n[] = {
+ BYTES_TO_T_UINT_8( 0xF7, 0xB1, 0x9F, 0x76, 0x71, 0xA9, 0xF0, 0xCA ),
+ BYTES_TO_T_UINT_8( 0x84, 0x61, 0xEC, 0xD2, 0xE8, 0xDC, 0x01, 0x00 ),
+ BYTES_TO_T_UINT_8( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ),
+ BYTES_TO_T_UINT_8( 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 ),
+};
+#endif /* MBEDCRYPTO_ECP_DP_SECP224K1_ENABLED */
+
+#if defined(MBEDCRYPTO_ECP_DP_SECP256K1_ENABLED)
+static const mbedcrypto_mpi_uint secp256k1_p[] = {
+ BYTES_TO_T_UINT_8( 0x2F, 0xFC, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+};
+static const mbedcrypto_mpi_uint secp256k1_a[] = {
+ BYTES_TO_T_UINT_2( 0x00, 0x00 ),
+};
+static const mbedcrypto_mpi_uint secp256k1_b[] = {
+ BYTES_TO_T_UINT_2( 0x07, 0x00 ),
+};
+static const mbedcrypto_mpi_uint secp256k1_gx[] = {
+ BYTES_TO_T_UINT_8( 0x98, 0x17, 0xF8, 0x16, 0x5B, 0x81, 0xF2, 0x59 ),
+ BYTES_TO_T_UINT_8( 0xD9, 0x28, 0xCE, 0x2D, 0xDB, 0xFC, 0x9B, 0x02 ),
+ BYTES_TO_T_UINT_8( 0x07, 0x0B, 0x87, 0xCE, 0x95, 0x62, 0xA0, 0x55 ),
+ BYTES_TO_T_UINT_8( 0xAC, 0xBB, 0xDC, 0xF9, 0x7E, 0x66, 0xBE, 0x79 ),
+};
+static const mbedcrypto_mpi_uint secp256k1_gy[] = {
+ BYTES_TO_T_UINT_8( 0xB8, 0xD4, 0x10, 0xFB, 0x8F, 0xD0, 0x47, 0x9C ),
+ BYTES_TO_T_UINT_8( 0x19, 0x54, 0x85, 0xA6, 0x48, 0xB4, 0x17, 0xFD ),
+ BYTES_TO_T_UINT_8( 0xA8, 0x08, 0x11, 0x0E, 0xFC, 0xFB, 0xA4, 0x5D ),
+ BYTES_TO_T_UINT_8( 0x65, 0xC4, 0xA3, 0x26, 0x77, 0xDA, 0x3A, 0x48 ),
+};
+static const mbedcrypto_mpi_uint secp256k1_n[] = {
+ BYTES_TO_T_UINT_8( 0x41, 0x41, 0x36, 0xD0, 0x8C, 0x5E, 0xD2, 0xBF ),
+ BYTES_TO_T_UINT_8( 0x3B, 0xA0, 0x48, 0xAF, 0xE6, 0xDC, 0xAE, 0xBA ),
+ BYTES_TO_T_UINT_8( 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+ BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ),
+};
+#endif /* MBEDCRYPTO_ECP_DP_SECP256K1_ENABLED */
+
+/*
+ * Domain parameters for brainpoolP256r1 (RFC 5639 3.4)
+ */
+#if defined(MBEDCRYPTO_ECP_DP_BP256R1_ENABLED)
+static const mbedcrypto_mpi_uint brainpoolP256r1_p[] = {
+ BYTES_TO_T_UINT_8( 0x77, 0x53, 0x6E, 0x1F, 0x1D, 0x48, 0x13, 0x20 ),
+ BYTES_TO_T_UINT_8( 0x28, 0x20, 0x26, 0xD5, 0x23, 0xF6, 0x3B, 0x6E ),
+ BYTES_TO_T_UINT_8( 0x72, 0x8D, 0x83, 0x9D, 0x90, 0x0A, 0x66, 0x3E ),
+ BYTES_TO_T_UINT_8( 0xBC, 0xA9, 0xEE, 0xA1, 0xDB, 0x57, 0xFB, 0xA9 ),
+};
+static const mbedcrypto_mpi_uint brainpoolP256r1_a[] = {
+ BYTES_TO_T_UINT_8( 0xD9, 0xB5, 0x30, 0xF3, 0x44, 0x4B, 0x4A, 0xE9 ),
+ BYTES_TO_T_UINT_8( 0x6C, 0x5C, 0xDC, 0x26, 0xC1, 0x55, 0x80, 0xFB ),
+ BYTES_TO_T_UINT_8( 0xE7, 0xFF, 0x7A, 0x41, 0x30, 0x75, 0xF6, 0xEE ),
+ BYTES_TO_T_UINT_8( 0x57, 0x30, 0x2C, 0xFC, 0x75, 0x09, 0x5A, 0x7D ),
+};
+static const mbedcrypto_mpi_uint brainpoolP256r1_b[] = {
+ BYTES_TO_T_UINT_8( 0xB6, 0x07, 0x8C, 0xFF, 0x18, 0xDC, 0xCC, 0x6B ),
+ BYTES_TO_T_UINT_8( 0xCE, 0xE1, 0xF7, 0x5C, 0x29, 0x16, 0x84, 0x95 ),
+ BYTES_TO_T_UINT_8( 0xBF, 0x7C, 0xD7, 0xBB, 0xD9, 0xB5, 0x30, 0xF3 ),
+ BYTES_TO_T_UINT_8( 0x44, 0x4B, 0x4A, 0xE9, 0x6C, 0x5C, 0xDC, 0x26 ),
+};
+static const mbedcrypto_mpi_uint brainpoolP256r1_gx[] = {
+ BYTES_TO_T_UINT_8( 0x62, 0x32, 0xCE, 0x9A, 0xBD, 0x53, 0x44, 0x3A ),
+ BYTES_TO_T_UINT_8( 0xC2, 0x23, 0xBD, 0xE3, 0xE1, 0x27, 0xDE, 0xB9 ),
+ BYTES_TO_T_UINT_8( 0xAF, 0xB7, 0x81, 0xFC, 0x2F, 0x48, 0x4B, 0x2C ),
+ BYTES_TO_T_UINT_8( 0xCB, 0x57, 0x7E, 0xCB, 0xB9, 0xAE, 0xD2, 0x8B ),
+};
+static const mbedcrypto_mpi_uint brainpoolP256r1_gy[] = {
+ BYTES_TO_T_UINT_8( 0x97, 0x69, 0x04, 0x2F, 0xC7, 0x54, 0x1D, 0x5C ),
+ BYTES_TO_T_UINT_8( 0x54, 0x8E, 0xED, 0x2D, 0x13, 0x45, 0x77, 0xC2 ),
+ BYTES_TO_T_UINT_8( 0xC9, 0x1D, 0x61, 0x14, 0x1A, 0x46, 0xF8, 0x97 ),
+ BYTES_TO_T_UINT_8( 0xFD, 0xC4, 0xDA, 0xC3, 0x35, 0xF8, 0x7E, 0x54 ),
+};
+static const mbedcrypto_mpi_uint brainpoolP256r1_n[] = {
+ BYTES_TO_T_UINT_8( 0xA7, 0x56, 0x48, 0x97, 0x82, 0x0E, 0x1E, 0x90 ),
+ BYTES_TO_T_UINT_8( 0xF7, 0xA6, 0x61, 0xB5, 0xA3, 0x7A, 0x39, 0x8C ),
+ BYTES_TO_T_UINT_8( 0x71, 0x8D, 0x83, 0x9D, 0x90, 0x0A, 0x66, 0x3E ),
+ BYTES_TO_T_UINT_8( 0xBC, 0xA9, 0xEE, 0xA1, 0xDB, 0x57, 0xFB, 0xA9 ),
+};
+#endif /* MBEDCRYPTO_ECP_DP_BP256R1_ENABLED */
+
+/*
+ * Domain parameters for brainpoolP384r1 (RFC 5639 3.6)
+ */
+#if defined(MBEDCRYPTO_ECP_DP_BP384R1_ENABLED)
+static const mbedcrypto_mpi_uint brainpoolP384r1_p[] = {
+ BYTES_TO_T_UINT_8( 0x53, 0xEC, 0x07, 0x31, 0x13, 0x00, 0x47, 0x87 ),
+ BYTES_TO_T_UINT_8( 0x71, 0x1A, 0x1D, 0x90, 0x29, 0xA7, 0xD3, 0xAC ),
+ BYTES_TO_T_UINT_8( 0x23, 0x11, 0xB7, 0x7F, 0x19, 0xDA, 0xB1, 0x12 ),
+ BYTES_TO_T_UINT_8( 0xB4, 0x56, 0x54, 0xED, 0x09, 0x71, 0x2F, 0x15 ),
+ BYTES_TO_T_UINT_8( 0xDF, 0x41, 0xE6, 0x50, 0x7E, 0x6F, 0x5D, 0x0F ),
+ BYTES_TO_T_UINT_8( 0x28, 0x6D, 0x38, 0xA3, 0x82, 0x1E, 0xB9, 0x8C ),
+};
+static const mbedcrypto_mpi_uint brainpoolP384r1_a[] = {
+ BYTES_TO_T_UINT_8( 0x26, 0x28, 0xCE, 0x22, 0xDD, 0xC7, 0xA8, 0x04 ),
+ BYTES_TO_T_UINT_8( 0xEB, 0xD4, 0x3A, 0x50, 0x4A, 0x81, 0xA5, 0x8A ),
+ BYTES_TO_T_UINT_8( 0x0F, 0xF9, 0x91, 0xBA, 0xEF, 0x65, 0x91, 0x13 ),
+ BYTES_TO_T_UINT_8( 0x87, 0x27, 0xB2, 0x4F, 0x8E, 0xA2, 0xBE, 0xC2 ),
+ BYTES_TO_T_UINT_8( 0xA0, 0xAF, 0x05, 0xCE, 0x0A, 0x08, 0x72, 0x3C ),
+ BYTES_TO_T_UINT_8( 0x0C, 0x15, 0x8C, 0x3D, 0xC6, 0x82, 0xC3, 0x7B ),
+};
+static const mbedcrypto_mpi_uint brainpoolP384r1_b[] = {
+ BYTES_TO_T_UINT_8( 0x11, 0x4C, 0x50, 0xFA, 0x96, 0x86, 0xB7, 0x3A ),
+ BYTES_TO_T_UINT_8( 0x94, 0xC9, 0xDB, 0x95, 0x02, 0x39, 0xB4, 0x7C ),
+ BYTES_TO_T_UINT_8( 0xD5, 0x62, 0xEB, 0x3E, 0xA5, 0x0E, 0x88, 0x2E ),
+ BYTES_TO_T_UINT_8( 0xA6, 0xD2, 0xDC, 0x07, 0xE1, 0x7D, 0xB7, 0x2F ),
+ BYTES_TO_T_UINT_8( 0x7C, 0x44, 0xF0, 0x16, 0x54, 0xB5, 0x39, 0x8B ),
+ BYTES_TO_T_UINT_8( 0x26, 0x28, 0xCE, 0x22, 0xDD, 0xC7, 0xA8, 0x04 ),
+};
+static const mbedcrypto_mpi_uint brainpoolP384r1_gx[] = {
+ BYTES_TO_T_UINT_8( 0x1E, 0xAF, 0xD4, 0x47, 0xE2, 0xB2, 0x87, 0xEF ),
+ BYTES_TO_T_UINT_8( 0xAA, 0x46, 0xD6, 0x36, 0x34, 0xE0, 0x26, 0xE8 ),
+ BYTES_TO_T_UINT_8( 0xE8, 0x10, 0xBD, 0x0C, 0xFE, 0xCA, 0x7F, 0xDB ),
+ BYTES_TO_T_UINT_8( 0xE3, 0x4F, 0xF1, 0x7E, 0xE7, 0xA3, 0x47, 0x88 ),
+ BYTES_TO_T_UINT_8( 0x6B, 0x3F, 0xC1, 0xB7, 0x81, 0x3A, 0xA6, 0xA2 ),
+ BYTES_TO_T_UINT_8( 0xFF, 0x45, 0xCF, 0x68, 0xF0, 0x64, 0x1C, 0x1D ),
+};
+static const mbedcrypto_mpi_uint brainpoolP384r1_gy[] = {
+ BYTES_TO_T_UINT_8( 0x15, 0x53, 0x3C, 0x26, 0x41, 0x03, 0x82, 0x42 ),
+ BYTES_TO_T_UINT_8( 0x11, 0x81, 0x91, 0x77, 0x21, 0x46, 0x46, 0x0E ),
+ BYTES_TO_T_UINT_8( 0x28, 0x29, 0x91, 0xF9, 0x4F, 0x05, 0x9C, 0xE1 ),
+ BYTES_TO_T_UINT_8( 0x64, 0x58, 0xEC, 0xFE, 0x29, 0x0B, 0xB7, 0x62 ),
+ BYTES_TO_T_UINT_8( 0x52, 0xD5, 0xCF, 0x95, 0x8E, 0xEB, 0xB1, 0x5C ),
+ BYTES_TO_T_UINT_8( 0xA4, 0xC2, 0xF9, 0x20, 0x75, 0x1D, 0xBE, 0x8A ),
+};
+static const mbedcrypto_mpi_uint brainpoolP384r1_n[] = {
+ BYTES_TO_T_UINT_8( 0x65, 0x65, 0x04, 0xE9, 0x02, 0x32, 0x88, 0x3B ),
+ BYTES_TO_T_UINT_8( 0x10, 0xC3, 0x7F, 0x6B, 0xAF, 0xB6, 0x3A, 0xCF ),
+ BYTES_TO_T_UINT_8( 0xA7, 0x25, 0x04, 0xAC, 0x6C, 0x6E, 0x16, 0x1F ),
+ BYTES_TO_T_UINT_8( 0xB3, 0x56, 0x54, 0xED, 0x09, 0x71, 0x2F, 0x15 ),
+ BYTES_TO_T_UINT_8( 0xDF, 0x41, 0xE6, 0x50, 0x7E, 0x6F, 0x5D, 0x0F ),
+ BYTES_TO_T_UINT_8( 0x28, 0x6D, 0x38, 0xA3, 0x82, 0x1E, 0xB9, 0x8C ),
+};
+#endif /* MBEDCRYPTO_ECP_DP_BP384R1_ENABLED */
+
+/*
+ * Domain parameters for brainpoolP512r1 (RFC 5639 3.7)
+ */
+#if defined(MBEDCRYPTO_ECP_DP_BP512R1_ENABLED)
+static const mbedcrypto_mpi_uint brainpoolP512r1_p[] = {
+ BYTES_TO_T_UINT_8( 0xF3, 0x48, 0x3A, 0x58, 0x56, 0x60, 0xAA, 0x28 ),
+ BYTES_TO_T_UINT_8( 0x85, 0xC6, 0x82, 0x2D, 0x2F, 0xFF, 0x81, 0x28 ),
+ BYTES_TO_T_UINT_8( 0xE6, 0x80, 0xA3, 0xE6, 0x2A, 0xA1, 0xCD, 0xAE ),
+ BYTES_TO_T_UINT_8( 0x42, 0x68, 0xC6, 0x9B, 0x00, 0x9B, 0x4D, 0x7D ),
+ BYTES_TO_T_UINT_8( 0x71, 0x08, 0x33, 0x70, 0xCA, 0x9C, 0x63, 0xD6 ),
+ BYTES_TO_T_UINT_8( 0x0E, 0xD2, 0xC9, 0xB3, 0xB3, 0x8D, 0x30, 0xCB ),
+ BYTES_TO_T_UINT_8( 0x07, 0xFC, 0xC9, 0x33, 0xAE, 0xE6, 0xD4, 0x3F ),
+ BYTES_TO_T_UINT_8( 0x8B, 0xC4, 0xE9, 0xDB, 0xB8, 0x9D, 0xDD, 0xAA ),
+};
+static const mbedcrypto_mpi_uint brainpoolP512r1_a[] = {
+ BYTES_TO_T_UINT_8( 0xCA, 0x94, 0xFC, 0x77, 0x4D, 0xAC, 0xC1, 0xE7 ),
+ BYTES_TO_T_UINT_8( 0xB9, 0xC7, 0xF2, 0x2B, 0xA7, 0x17, 0x11, 0x7F ),
+ BYTES_TO_T_UINT_8( 0xB5, 0xC8, 0x9A, 0x8B, 0xC9, 0xF1, 0x2E, 0x0A ),
+ BYTES_TO_T_UINT_8( 0xA1, 0x3A, 0x25, 0xA8, 0x5A, 0x5D, 0xED, 0x2D ),
+ BYTES_TO_T_UINT_8( 0xBC, 0x63, 0x98, 0xEA, 0xCA, 0x41, 0x34, 0xA8 ),
+ BYTES_TO_T_UINT_8( 0x10, 0x16, 0xF9, 0x3D, 0x8D, 0xDD, 0xCB, 0x94 ),
+ BYTES_TO_T_UINT_8( 0xC5, 0x4C, 0x23, 0xAC, 0x45, 0x71, 0x32, 0xE2 ),
+ BYTES_TO_T_UINT_8( 0x89, 0x3B, 0x60, 0x8B, 0x31, 0xA3, 0x30, 0x78 ),
+};
+static const mbedcrypto_mpi_uint brainpoolP512r1_b[] = {
+ BYTES_TO_T_UINT_8( 0x23, 0xF7, 0x16, 0x80, 0x63, 0xBD, 0x09, 0x28 ),
+ BYTES_TO_T_UINT_8( 0xDD, 0xE5, 0xBA, 0x5E, 0xB7, 0x50, 0x40, 0x98 ),
+ BYTES_TO_T_UINT_8( 0x67, 0x3E, 0x08, 0xDC, 0xCA, 0x94, 0xFC, 0x77 ),
+ BYTES_TO_T_UINT_8( 0x4D, 0xAC, 0xC1, 0xE7, 0xB9, 0xC7, 0xF2, 0x2B ),
+ BYTES_TO_T_UINT_8( 0xA7, 0x17, 0x11, 0x7F, 0xB5, 0xC8, 0x9A, 0x8B ),
+ BYTES_TO_T_UINT_8( 0xC9, 0xF1, 0x2E, 0x0A, 0xA1, 0x3A, 0x25, 0xA8 ),
+ BYTES_TO_T_UINT_8( 0x5A, 0x5D, 0xED, 0x2D, 0xBC, 0x63, 0x98, 0xEA ),
+ BYTES_TO_T_UINT_8( 0xCA, 0x41, 0x34, 0xA8, 0x10, 0x16, 0xF9, 0x3D ),
+};
+static const mbedcrypto_mpi_uint brainpoolP512r1_gx[] = {
+ BYTES_TO_T_UINT_8( 0x22, 0xF8, 0xB9, 0xBC, 0x09, 0x22, 0x35, 0x8B ),
+ BYTES_TO_T_UINT_8( 0x68, 0x5E, 0x6A, 0x40, 0x47, 0x50, 0x6D, 0x7C ),
+ BYTES_TO_T_UINT_8( 0x5F, 0x7D, 0xB9, 0x93, 0x7B, 0x68, 0xD1, 0x50 ),
+ BYTES_TO_T_UINT_8( 0x8D, 0xD4, 0xD0, 0xE2, 0x78, 0x1F, 0x3B, 0xFF ),
+ BYTES_TO_T_UINT_8( 0x8E, 0x09, 0xD0, 0xF4, 0xEE, 0x62, 0x3B, 0xB4 ),
+ BYTES_TO_T_UINT_8( 0xC1, 0x16, 0xD9, 0xB5, 0x70, 0x9F, 0xED, 0x85 ),
+ BYTES_TO_T_UINT_8( 0x93, 0x6A, 0x4C, 0x9C, 0x2E, 0x32, 0x21, 0x5A ),
+ BYTES_TO_T_UINT_8( 0x64, 0xD9, 0x2E, 0xD8, 0xBD, 0xE4, 0xAE, 0x81 ),
+};
+static const mbedcrypto_mpi_uint brainpoolP512r1_gy[] = {
+ BYTES_TO_T_UINT_8( 0x92, 0x08, 0xD8, 0x3A, 0x0F, 0x1E, 0xCD, 0x78 ),
+ BYTES_TO_T_UINT_8( 0x06, 0x54, 0xF0, 0xA8, 0x2F, 0x2B, 0xCA, 0xD1 ),
+ BYTES_TO_T_UINT_8( 0xAE, 0x63, 0x27, 0x8A, 0xD8, 0x4B, 0xCA, 0x5B ),
+ BYTES_TO_T_UINT_8( 0x5E, 0x48, 0x5F, 0x4A, 0x49, 0xDE, 0xDC, 0xB2 ),
+ BYTES_TO_T_UINT_8( 0x11, 0x81, 0x1F, 0x88, 0x5B, 0xC5, 0x00, 0xA0 ),
+ BYTES_TO_T_UINT_8( 0x1A, 0x7B, 0xA5, 0x24, 0x00, 0xF7, 0x09, 0xF2 ),
+ BYTES_TO_T_UINT_8( 0xFD, 0x22, 0x78, 0xCF, 0xA9, 0xBF, 0xEA, 0xC0 ),
+ BYTES_TO_T_UINT_8( 0xEC, 0x32, 0x63, 0x56, 0x5D, 0x38, 0xDE, 0x7D ),
+};
+static const mbedcrypto_mpi_uint brainpoolP512r1_n[] = {
+ BYTES_TO_T_UINT_8( 0x69, 0x00, 0xA9, 0x9C, 0x82, 0x96, 0x87, 0xB5 ),
+ BYTES_TO_T_UINT_8( 0xDD, 0xDA, 0x5D, 0x08, 0x81, 0xD3, 0xB1, 0x1D ),
+ BYTES_TO_T_UINT_8( 0x47, 0x10, 0xAC, 0x7F, 0x19, 0x61, 0x86, 0x41 ),
+ BYTES_TO_T_UINT_8( 0x19, 0x26, 0xA9, 0x4C, 0x41, 0x5C, 0x3E, 0x55 ),
+ BYTES_TO_T_UINT_8( 0x70, 0x08, 0x33, 0x70, 0xCA, 0x9C, 0x63, 0xD6 ),
+ BYTES_TO_T_UINT_8( 0x0E, 0xD2, 0xC9, 0xB3, 0xB3, 0x8D, 0x30, 0xCB ),
+ BYTES_TO_T_UINT_8( 0x07, 0xFC, 0xC9, 0x33, 0xAE, 0xE6, 0xD4, 0x3F ),
+ BYTES_TO_T_UINT_8( 0x8B, 0xC4, 0xE9, 0xDB, 0xB8, 0x9D, 0xDD, 0xAA ),
+};
+#endif /* MBEDCRYPTO_ECP_DP_BP512R1_ENABLED */
+
+/*
+ * Create an MPI from embedded constants
+ * (assumes len is an exact multiple of sizeof mbedcrypto_mpi_uint)
+ */
+static inline void ecp_mpi_load( mbedcrypto_mpi *X, const mbedcrypto_mpi_uint *p, size_t len )
+{
+ X->s = 1;
+ X->n = len / sizeof( mbedcrypto_mpi_uint );
+ X->p = (mbedcrypto_mpi_uint *) p;
+}
+
+/*
+ * Set an MPI to static value 1
+ */
+static inline void ecp_mpi_set1( mbedcrypto_mpi *X )
+{
+ static mbedcrypto_mpi_uint one[] = { 1 };
+ X->s = 1;
+ X->n = 1;
+ X->p = one;
+}
+
+/*
+ * Make group available from embedded constants
+ */
+static int ecp_group_load( mbedcrypto_ecp_group *grp,
+ const mbedcrypto_mpi_uint *p, size_t plen,
+ const mbedcrypto_mpi_uint *a, size_t alen,
+ const mbedcrypto_mpi_uint *b, size_t blen,
+ const mbedcrypto_mpi_uint *gx, size_t gxlen,
+ const mbedcrypto_mpi_uint *gy, size_t gylen,
+ const mbedcrypto_mpi_uint *n, size_t nlen)
+{
+ ecp_mpi_load( &grp->P, p, plen );
+ if( a != NULL )
+ ecp_mpi_load( &grp->A, a, alen );
+ ecp_mpi_load( &grp->B, b, blen );
+ ecp_mpi_load( &grp->N, n, nlen );
+
+ ecp_mpi_load( &grp->G.X, gx, gxlen );
+ ecp_mpi_load( &grp->G.Y, gy, gylen );
+ ecp_mpi_set1( &grp->G.Z );
+
+ grp->pbits = mbedcrypto_mpi_bitlen( &grp->P );
+ grp->nbits = mbedcrypto_mpi_bitlen( &grp->N );
+
+ grp->h = 1;
+
+ return( 0 );
+}
+
+#if defined(MBEDCRYPTO_ECP_NIST_OPTIM)
+/* Forward declarations */
+#if defined(MBEDCRYPTO_ECP_DP_SECP192R1_ENABLED)
+static int ecp_mod_p192( mbedcrypto_mpi * );
+#endif
+#if defined(MBEDCRYPTO_ECP_DP_SECP224R1_ENABLED)
+static int ecp_mod_p224( mbedcrypto_mpi * );
+#endif
+#if defined(MBEDCRYPTO_ECP_DP_SECP256R1_ENABLED)
+static int ecp_mod_p256( mbedcrypto_mpi * );
+#endif
+#if defined(MBEDCRYPTO_ECP_DP_SECP384R1_ENABLED)
+static int ecp_mod_p384( mbedcrypto_mpi * );
+#endif
+#if defined(MBEDCRYPTO_ECP_DP_SECP521R1_ENABLED)
+static int ecp_mod_p521( mbedcrypto_mpi * );
+#endif
+
+#define NIST_MODP( P ) grp->modp = ecp_mod_ ## P;
+#else
+#define NIST_MODP( P )
+#endif /* MBEDCRYPTO_ECP_NIST_OPTIM */
+
+/* Additional forward declarations */
+#if defined(MBEDCRYPTO_ECP_DP_CURVE25519_ENABLED)
+static int ecp_mod_p255( mbedcrypto_mpi * );
+#endif
+#if defined(MBEDCRYPTO_ECP_DP_CURVE448_ENABLED)
+static int ecp_mod_p448( mbedcrypto_mpi * );
+#endif
+#if defined(MBEDCRYPTO_ECP_DP_SECP192K1_ENABLED)
+static int ecp_mod_p192k1( mbedcrypto_mpi * );
+#endif
+#if defined(MBEDCRYPTO_ECP_DP_SECP224K1_ENABLED)
+static int ecp_mod_p224k1( mbedcrypto_mpi * );
+#endif
+#if defined(MBEDCRYPTO_ECP_DP_SECP256K1_ENABLED)
+static int ecp_mod_p256k1( mbedcrypto_mpi * );
+#endif
+
+#define LOAD_GROUP_A( G ) ecp_group_load( grp, \
+ G ## _p, sizeof( G ## _p ), \
+ G ## _a, sizeof( G ## _a ), \
+ G ## _b, sizeof( G ## _b ), \
+ G ## _gx, sizeof( G ## _gx ), \
+ G ## _gy, sizeof( G ## _gy ), \
+ G ## _n, sizeof( G ## _n ) )
+
+#define LOAD_GROUP( G ) ecp_group_load( grp, \
+ G ## _p, sizeof( G ## _p ), \
+ NULL, 0, \
+ G ## _b, sizeof( G ## _b ), \
+ G ## _gx, sizeof( G ## _gx ), \
+ G ## _gy, sizeof( G ## _gy ), \
+ G ## _n, sizeof( G ## _n ) )
+
+#if defined(MBEDCRYPTO_ECP_DP_CURVE25519_ENABLED)
+/*
+ * Specialized function for creating the Curve25519 group
+ */
+static int ecp_use_curve25519( mbedcrypto_ecp_group *grp )
+{
+ int ret;
+
+ /* Actually ( A + 2 ) / 4 */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_string( &grp->A, 16, "01DB42" ) );
+
+ /* P = 2^255 - 19 */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_lset( &grp->P, 1 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_l( &grp->P, 255 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_int( &grp->P, &grp->P, 19 ) );
+ grp->pbits = mbedcrypto_mpi_bitlen( &grp->P );
+
+ /* N = 2^252 + 27742317777372353535851937790883648493 */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_string( &grp->N, 16,
+ "14DEF9DEA2F79CD65812631A5CF5D3ED" ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_set_bit( &grp->N, 252, 1 ) );
+
+ /* Y intentionally not set, since we use x/z coordinates.
+ * This is used as a marker to identify Montgomery curves! */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_lset( &grp->G.X, 9 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_lset( &grp->G.Z, 1 ) );
+ mbedcrypto_mpi_free( &grp->G.Y );
+
+ /* Actually, the required msb for private keys */
+ grp->nbits = 254;
+
+cleanup:
+ if( ret != 0 )
+ mbedcrypto_ecp_group_free( grp );
+
+ return( ret );
+}
+#endif /* MBEDCRYPTO_ECP_DP_CURVE25519_ENABLED */
+
+#if defined(MBEDCRYPTO_ECP_DP_CURVE448_ENABLED)
+/*
+ * Specialized function for creating the Curve448 group
+ */
+static int ecp_use_curve448( mbedcrypto_ecp_group *grp )
+{
+ mbedcrypto_mpi Ns;
+ int ret;
+
+ mbedcrypto_mpi_init( &Ns );
+
+ /* Actually ( A + 2 ) / 4 */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_string( &grp->A, 16, "98AA" ) );
+
+ /* P = 2^448 - 2^224 - 1 */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_lset( &grp->P, 1 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_l( &grp->P, 224 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_int( &grp->P, &grp->P, 1 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_l( &grp->P, 224 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_int( &grp->P, &grp->P, 1 ) );
+ grp->pbits = mbedcrypto_mpi_bitlen( &grp->P );
+
+ /* Y intentionally not set, since we use x/z coordinates.
+ * This is used as a marker to identify Montgomery curves! */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_lset( &grp->G.X, 5 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_lset( &grp->G.Z, 1 ) );
+ mbedcrypto_mpi_free( &grp->G.Y );
+
+ /* N = 2^446 - 13818066809895115352007386748515426880336692474882178609894547503885 */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_set_bit( &grp->N, 446, 1 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_string( &Ns, 16,
+ "8335DC163BB124B65129C96FDE933D8D723A70AADC873D6D54A7BB0D" ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &grp->N, &grp->N, &Ns ) );
+
+ /* Actually, the required msb for private keys */
+ grp->nbits = 447;
+
+cleanup:
+ mbedcrypto_mpi_free( &Ns );
+ if( ret != 0 )
+ mbedcrypto_ecp_group_free( grp );
+
+ return( ret );
+}
+#endif /* MBEDCRYPTO_ECP_DP_CURVE448_ENABLED */
+
+/*
+ * Set a group using well-known domain parameters
+ */
+int mbedcrypto_ecp_group_load( mbedcrypto_ecp_group *grp, mbedcrypto_ecp_group_id id )
+{
+ mbedcrypto_ecp_group_free( grp );
+
+ grp->id = id;
+
+ switch( id )
+ {
+#if defined(MBEDCRYPTO_ECP_DP_SECP192R1_ENABLED)
+ case MBEDCRYPTO_ECP_DP_SECP192R1:
+ NIST_MODP( p192 );
+ return( LOAD_GROUP( secp192r1 ) );
+#endif /* MBEDCRYPTO_ECP_DP_SECP192R1_ENABLED */
+
+#if defined(MBEDCRYPTO_ECP_DP_SECP224R1_ENABLED)
+ case MBEDCRYPTO_ECP_DP_SECP224R1:
+ NIST_MODP( p224 );
+ return( LOAD_GROUP( secp224r1 ) );
+#endif /* MBEDCRYPTO_ECP_DP_SECP224R1_ENABLED */
+
+#if defined(MBEDCRYPTO_ECP_DP_SECP256R1_ENABLED)
+ case MBEDCRYPTO_ECP_DP_SECP256R1:
+ NIST_MODP( p256 );
+ return( LOAD_GROUP( secp256r1 ) );
+#endif /* MBEDCRYPTO_ECP_DP_SECP256R1_ENABLED */
+
+#if defined(MBEDCRYPTO_ECP_DP_SECP384R1_ENABLED)
+ case MBEDCRYPTO_ECP_DP_SECP384R1:
+ NIST_MODP( p384 );
+ return( LOAD_GROUP( secp384r1 ) );
+#endif /* MBEDCRYPTO_ECP_DP_SECP384R1_ENABLED */
+
+#if defined(MBEDCRYPTO_ECP_DP_SECP521R1_ENABLED)
+ case MBEDCRYPTO_ECP_DP_SECP521R1:
+ NIST_MODP( p521 );
+ return( LOAD_GROUP( secp521r1 ) );
+#endif /* MBEDCRYPTO_ECP_DP_SECP521R1_ENABLED */
+
+#if defined(MBEDCRYPTO_ECP_DP_SECP192K1_ENABLED)
+ case MBEDCRYPTO_ECP_DP_SECP192K1:
+ grp->modp = ecp_mod_p192k1;
+ return( LOAD_GROUP_A( secp192k1 ) );
+#endif /* MBEDCRYPTO_ECP_DP_SECP192K1_ENABLED */
+
+#if defined(MBEDCRYPTO_ECP_DP_SECP224K1_ENABLED)
+ case MBEDCRYPTO_ECP_DP_SECP224K1:
+ grp->modp = ecp_mod_p224k1;
+ return( LOAD_GROUP_A( secp224k1 ) );
+#endif /* MBEDCRYPTO_ECP_DP_SECP224K1_ENABLED */
+
+#if defined(MBEDCRYPTO_ECP_DP_SECP256K1_ENABLED)
+ case MBEDCRYPTO_ECP_DP_SECP256K1:
+ grp->modp = ecp_mod_p256k1;
+ return( LOAD_GROUP_A( secp256k1 ) );
+#endif /* MBEDCRYPTO_ECP_DP_SECP256K1_ENABLED */
+
+#if defined(MBEDCRYPTO_ECP_DP_BP256R1_ENABLED)
+ case MBEDCRYPTO_ECP_DP_BP256R1:
+ return( LOAD_GROUP_A( brainpoolP256r1 ) );
+#endif /* MBEDCRYPTO_ECP_DP_BP256R1_ENABLED */
+
+#if defined(MBEDCRYPTO_ECP_DP_BP384R1_ENABLED)
+ case MBEDCRYPTO_ECP_DP_BP384R1:
+ return( LOAD_GROUP_A( brainpoolP384r1 ) );
+#endif /* MBEDCRYPTO_ECP_DP_BP384R1_ENABLED */
+
+#if defined(MBEDCRYPTO_ECP_DP_BP512R1_ENABLED)
+ case MBEDCRYPTO_ECP_DP_BP512R1:
+ return( LOAD_GROUP_A( brainpoolP512r1 ) );
+#endif /* MBEDCRYPTO_ECP_DP_BP512R1_ENABLED */
+
+#if defined(MBEDCRYPTO_ECP_DP_CURVE25519_ENABLED)
+ case MBEDCRYPTO_ECP_DP_CURVE25519:
+ grp->modp = ecp_mod_p255;
+ return( ecp_use_curve25519( grp ) );
+#endif /* MBEDCRYPTO_ECP_DP_CURVE25519_ENABLED */
+
+#if defined(MBEDCRYPTO_ECP_DP_CURVE448_ENABLED)
+ case MBEDCRYPTO_ECP_DP_CURVE448:
+ grp->modp = ecp_mod_p448;
+ return( ecp_use_curve448( grp ) );
+#endif /* MBEDCRYPTO_ECP_DP_CURVE448_ENABLED */
+
+ default:
+ mbedcrypto_ecp_group_free( grp );
+ return( MBEDCRYPTO_ERR_ECP_FEATURE_UNAVAILABLE );
+ }
+}
+
+#if defined(MBEDCRYPTO_ECP_NIST_OPTIM)
+/*
+ * Fast reduction modulo the primes used by the NIST curves.
+ *
+ * These functions are critical for speed, but not needed for correct
+ * operations. So, we make the choice to heavily rely on the internals of our
+ * bignum library, which creates a tight coupling between these functions and
+ * our MPI implementation. However, the coupling between the ECP module and
+ * MPI remains loose, since these functions can be deactivated at will.
+ */
+
+#if defined(MBEDCRYPTO_ECP_DP_SECP192R1_ENABLED)
+/*
+ * Compared to the way things are presented in FIPS 186-3 D.2,
+ * we proceed in columns, from right (least significant chunk) to left,
+ * adding chunks to N in place, and keeping a carry for the next chunk.
+ * This avoids moving things around in memory, and uselessly adding zeros,
+ * compared to the more straightforward, line-oriented approach.
+ *
+ * For this prime we need to handle data in chunks of 64 bits.
+ * Since this is always a multiple of our basic mbedcrypto_mpi_uint, we can
+ * use a mbedcrypto_mpi_uint * to designate such a chunk, and small loops to handle it.
+ */
+
+/* Add 64-bit chunks (dst += src) and update carry */
+static inline void add64( mbedcrypto_mpi_uint *dst, mbedcrypto_mpi_uint *src, mbedcrypto_mpi_uint *carry )
+{
+ unsigned char i;
+ mbedcrypto_mpi_uint c = 0;
+ for( i = 0; i < 8 / sizeof( mbedcrypto_mpi_uint ); i++, dst++, src++ )
+ {
+ *dst += c; c = ( *dst < c );
+ *dst += *src; c += ( *dst < *src );
+ }
+ *carry += c;
+}
+
+/* Add carry to a 64-bit chunk and update carry */
+static inline void carry64( mbedcrypto_mpi_uint *dst, mbedcrypto_mpi_uint *carry )
+{
+ unsigned char i;
+ for( i = 0; i < 8 / sizeof( mbedcrypto_mpi_uint ); i++, dst++ )
+ {
+ *dst += *carry;
+ *carry = ( *dst < *carry );
+ }
+}
+
+#define WIDTH 8 / sizeof( mbedcrypto_mpi_uint )
+#define A( i ) N->p + i * WIDTH
+#define ADD( i ) add64( p, A( i ), &c )
+#define NEXT p += WIDTH; carry64( p, &c )
+#define LAST p += WIDTH; *p = c; while( ++p < end ) *p = 0
+
+/*
+ * Fast quasi-reduction modulo p192 (FIPS 186-3 D.2.1)
+ */
+static int ecp_mod_p192( mbedcrypto_mpi *N )
+{
+ int ret;
+ mbedcrypto_mpi_uint c = 0;
+ mbedcrypto_mpi_uint *p, *end;
+
+ /* Make sure we have enough blocks so that A(5) is legal */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_grow( N, 6 * WIDTH ) );
+
+ p = N->p;
+ end = p + N->n;
+
+ ADD( 3 ); ADD( 5 ); NEXT; // A0 += A3 + A5
+ ADD( 3 ); ADD( 4 ); ADD( 5 ); NEXT; // A1 += A3 + A4 + A5
+ ADD( 4 ); ADD( 5 ); LAST; // A2 += A4 + A5
+
+cleanup:
+ return( ret );
+}
+
+#undef WIDTH
+#undef A
+#undef ADD
+#undef NEXT
+#undef LAST
+#endif /* MBEDCRYPTO_ECP_DP_SECP192R1_ENABLED */
+
+#if defined(MBEDCRYPTO_ECP_DP_SECP224R1_ENABLED) || \
+ defined(MBEDCRYPTO_ECP_DP_SECP256R1_ENABLED) || \
+ defined(MBEDCRYPTO_ECP_DP_SECP384R1_ENABLED)
+/*
+ * The reader is advised to first understand ecp_mod_p192() since the same
+ * general structure is used here, but with additional complications:
+ * (1) chunks of 32 bits, and (2) subtractions.
+ */
+
+/*
+ * For these primes, we need to handle data in chunks of 32 bits.
+ * This makes it more complicated if we use 64 bits limbs in MPI,
+ * which prevents us from using a uniform access method as for p192.
+ *
+ * So, we define a mini abstraction layer to access 32 bit chunks,
+ * load them in 'cur' for work, and store them back from 'cur' when done.
+ *
+ * While at it, also define the size of N in terms of 32-bit chunks.
+ */
+#define LOAD32 cur = A( i );
+
+#if defined(MBEDCRYPTO_HAVE_INT32) /* 32 bit */
+
+#define MAX32 N->n
+#define A( j ) N->p[j]
+#define STORE32 N->p[i] = cur;
+
+#else /* 64-bit */
+
+#define MAX32 N->n * 2
+#define A( j ) j % 2 ? (uint32_t)( N->p[j/2] >> 32 ) : (uint32_t)( N->p[j/2] )
+#define STORE32 \
+ if( i % 2 ) { \
+ N->p[i/2] &= 0x00000000FFFFFFFF; \
+ N->p[i/2] |= ((mbedcrypto_mpi_uint) cur) << 32; \
+ } else { \
+ N->p[i/2] &= 0xFFFFFFFF00000000; \
+ N->p[i/2] |= (mbedcrypto_mpi_uint) cur; \
+ }
+
+#endif /* sizeof( mbedcrypto_mpi_uint ) */
+
+/*
+ * Helpers for addition and subtraction of chunks, with signed carry.
+ */
+static inline void add32( uint32_t *dst, uint32_t src, signed char *carry )
+{
+ *dst += src;
+ *carry += ( *dst < src );
+}
+
+static inline void sub32( uint32_t *dst, uint32_t src, signed char *carry )
+{
+ *carry -= ( *dst < src );
+ *dst -= src;
+}
+
+#define ADD( j ) add32( &cur, A( j ), &c );
+#define SUB( j ) sub32( &cur, A( j ), &c );
+
+/*
+ * Helpers for the main 'loop'
+ * (see fix_negative for the motivation of C)
+ */
+#define INIT( b ) \
+ int ret; \
+ signed char c = 0, cc; \
+ uint32_t cur; \
+ size_t i = 0, bits = b; \
+ mbedcrypto_mpi C; \
+ mbedcrypto_mpi_uint Cp[ b / 8 / sizeof( mbedcrypto_mpi_uint) + 1 ]; \
+ \
+ C.s = 1; \
+ C.n = b / 8 / sizeof( mbedcrypto_mpi_uint) + 1; \
+ C.p = Cp; \
+ memset( Cp, 0, C.n * sizeof( mbedcrypto_mpi_uint ) ); \
+ \
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_grow( N, b * 2 / 8 / sizeof( mbedcrypto_mpi_uint ) ) ); \
+ LOAD32;
+
+#define NEXT \
+ STORE32; i++; LOAD32; \
+ cc = c; c = 0; \
+ if( cc < 0 ) \
+ sub32( &cur, -cc, &c ); \
+ else \
+ add32( &cur, cc, &c ); \
+
+#define LAST \
+ STORE32; i++; \
+ cur = c > 0 ? c : 0; STORE32; \
+ cur = 0; while( ++i < MAX32 ) { STORE32; } \
+ if( c < 0 ) fix_negative( N, c, &C, bits );
+
+/*
+ * If the result is negative, we get it in the form
+ * c * 2^(bits + 32) + N, with c negative and N positive shorter than 'bits'
+ */
+static inline int fix_negative( mbedcrypto_mpi *N, signed char c, mbedcrypto_mpi *C, size_t bits )
+{
+ int ret;
+
+ /* C = - c * 2^(bits + 32) */
+#if !defined(MBEDCRYPTO_HAVE_INT64)
+ ((void) bits);
+#else
+ if( bits == 224 )
+ C->p[ C->n - 1 ] = ((mbedcrypto_mpi_uint) -c) << 32;
+ else
+#endif
+ C->p[ C->n - 1 ] = (mbedcrypto_mpi_uint) -c;
+
+ /* N = - ( C - N ) */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_abs( N, C, N ) );
+ N->s = -1;
+
+cleanup:
+
+ return( ret );
+}
+
+#if defined(MBEDCRYPTO_ECP_DP_SECP224R1_ENABLED)
+/*
+ * Fast quasi-reduction modulo p224 (FIPS 186-3 D.2.2)
+ */
+static int ecp_mod_p224( mbedcrypto_mpi *N )
+{
+ INIT( 224 );
+
+ SUB( 7 ); SUB( 11 ); NEXT; // A0 += -A7 - A11
+ SUB( 8 ); SUB( 12 ); NEXT; // A1 += -A8 - A12
+ SUB( 9 ); SUB( 13 ); NEXT; // A2 += -A9 - A13
+ SUB( 10 ); ADD( 7 ); ADD( 11 ); NEXT; // A3 += -A10 + A7 + A11
+ SUB( 11 ); ADD( 8 ); ADD( 12 ); NEXT; // A4 += -A11 + A8 + A12
+ SUB( 12 ); ADD( 9 ); ADD( 13 ); NEXT; // A5 += -A12 + A9 + A13
+ SUB( 13 ); ADD( 10 ); LAST; // A6 += -A13 + A10
+
+cleanup:
+ return( ret );
+}
+#endif /* MBEDCRYPTO_ECP_DP_SECP224R1_ENABLED */
+
+#if defined(MBEDCRYPTO_ECP_DP_SECP256R1_ENABLED)
+/*
+ * Fast quasi-reduction modulo p256 (FIPS 186-3 D.2.3)
+ */
+static int ecp_mod_p256( mbedcrypto_mpi *N )
+{
+ INIT( 256 );
+
+ ADD( 8 ); ADD( 9 );
+ SUB( 11 ); SUB( 12 ); SUB( 13 ); SUB( 14 ); NEXT; // A0
+
+ ADD( 9 ); ADD( 10 );
+ SUB( 12 ); SUB( 13 ); SUB( 14 ); SUB( 15 ); NEXT; // A1
+
+ ADD( 10 ); ADD( 11 );
+ SUB( 13 ); SUB( 14 ); SUB( 15 ); NEXT; // A2
+
+ ADD( 11 ); ADD( 11 ); ADD( 12 ); ADD( 12 ); ADD( 13 );
+ SUB( 15 ); SUB( 8 ); SUB( 9 ); NEXT; // A3
+
+ ADD( 12 ); ADD( 12 ); ADD( 13 ); ADD( 13 ); ADD( 14 );
+ SUB( 9 ); SUB( 10 ); NEXT; // A4
+
+ ADD( 13 ); ADD( 13 ); ADD( 14 ); ADD( 14 ); ADD( 15 );
+ SUB( 10 ); SUB( 11 ); NEXT; // A5
+
+ ADD( 14 ); ADD( 14 ); ADD( 15 ); ADD( 15 ); ADD( 14 ); ADD( 13 );
+ SUB( 8 ); SUB( 9 ); NEXT; // A6
+
+ ADD( 15 ); ADD( 15 ); ADD( 15 ); ADD( 8 );
+ SUB( 10 ); SUB( 11 ); SUB( 12 ); SUB( 13 ); LAST; // A7
+
+cleanup:
+ return( ret );
+}
+#endif /* MBEDCRYPTO_ECP_DP_SECP256R1_ENABLED */
+
+#if defined(MBEDCRYPTO_ECP_DP_SECP384R1_ENABLED)
+/*
+ * Fast quasi-reduction modulo p384 (FIPS 186-3 D.2.4)
+ */
+static int ecp_mod_p384( mbedcrypto_mpi *N )
+{
+ INIT( 384 );
+
+ ADD( 12 ); ADD( 21 ); ADD( 20 );
+ SUB( 23 ); NEXT; // A0
+
+ ADD( 13 ); ADD( 22 ); ADD( 23 );
+ SUB( 12 ); SUB( 20 ); NEXT; // A2
+
+ ADD( 14 ); ADD( 23 );
+ SUB( 13 ); SUB( 21 ); NEXT; // A2
+
+ ADD( 15 ); ADD( 12 ); ADD( 20 ); ADD( 21 );
+ SUB( 14 ); SUB( 22 ); SUB( 23 ); NEXT; // A3
+
+ ADD( 21 ); ADD( 21 ); ADD( 16 ); ADD( 13 ); ADD( 12 ); ADD( 20 ); ADD( 22 );
+ SUB( 15 ); SUB( 23 ); SUB( 23 ); NEXT; // A4
+
+ ADD( 22 ); ADD( 22 ); ADD( 17 ); ADD( 14 ); ADD( 13 ); ADD( 21 ); ADD( 23 );
+ SUB( 16 ); NEXT; // A5
+
+ ADD( 23 ); ADD( 23 ); ADD( 18 ); ADD( 15 ); ADD( 14 ); ADD( 22 );
+ SUB( 17 ); NEXT; // A6
+
+ ADD( 19 ); ADD( 16 ); ADD( 15 ); ADD( 23 );
+ SUB( 18 ); NEXT; // A7
+
+ ADD( 20 ); ADD( 17 ); ADD( 16 );
+ SUB( 19 ); NEXT; // A8
+
+ ADD( 21 ); ADD( 18 ); ADD( 17 );
+ SUB( 20 ); NEXT; // A9
+
+ ADD( 22 ); ADD( 19 ); ADD( 18 );
+ SUB( 21 ); NEXT; // A10
+
+ ADD( 23 ); ADD( 20 ); ADD( 19 );
+ SUB( 22 ); LAST; // A11
+
+cleanup:
+ return( ret );
+}
+#endif /* MBEDCRYPTO_ECP_DP_SECP384R1_ENABLED */
+
+#undef A
+#undef LOAD32
+#undef STORE32
+#undef MAX32
+#undef INIT
+#undef NEXT
+#undef LAST
+
+#endif /* MBEDCRYPTO_ECP_DP_SECP224R1_ENABLED ||
+ MBEDCRYPTO_ECP_DP_SECP256R1_ENABLED ||
+ MBEDCRYPTO_ECP_DP_SECP384R1_ENABLED */
+
+#if defined(MBEDCRYPTO_ECP_DP_SECP521R1_ENABLED)
+/*
+ * Here we have an actual Mersenne prime, so things are more straightforward.
+ * However, chunks are aligned on a 'weird' boundary (521 bits).
+ */
+
+/* Size of p521 in terms of mbedcrypto_mpi_uint */
+#define P521_WIDTH ( 521 / 8 / sizeof( mbedcrypto_mpi_uint ) + 1 )
+
+/* Bits to keep in the most significant mbedcrypto_mpi_uint */
+#define P521_MASK 0x01FF
+
+/*
+ * Fast quasi-reduction modulo p521 (FIPS 186-3 D.2.5)
+ * Write N as A1 + 2^521 A0, return A0 + A1
+ */
+static int ecp_mod_p521( mbedcrypto_mpi *N )
+{
+ int ret;
+ size_t i;
+ mbedcrypto_mpi M;
+ mbedcrypto_mpi_uint Mp[P521_WIDTH + 1];
+ /* Worst case for the size of M is when mbedcrypto_mpi_uint is 16 bits:
+ * we need to hold bits 513 to 1056, which is 34 limbs, that is
+ * P521_WIDTH + 1. Otherwise P521_WIDTH is enough. */
+
+ if( N->n < P521_WIDTH )
+ return( 0 );
+
+ /* M = A1 */
+ M.s = 1;
+ M.n = N->n - ( P521_WIDTH - 1 );
+ if( M.n > P521_WIDTH + 1 )
+ M.n = P521_WIDTH + 1;
+ M.p = Mp;
+ memcpy( Mp, N->p + P521_WIDTH - 1, M.n * sizeof( mbedcrypto_mpi_uint ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_r( &M, 521 % ( 8 * sizeof( mbedcrypto_mpi_uint ) ) ) );
+
+ /* N = A0 */
+ N->p[P521_WIDTH - 1] &= P521_MASK;
+ for( i = P521_WIDTH; i < N->n; i++ )
+ N->p[i] = 0;
+
+ /* N = A0 + A1 */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_abs( N, N, &M ) );
+
+cleanup:
+ return( ret );
+}
+
+#undef P521_WIDTH
+#undef P521_MASK
+#endif /* MBEDCRYPTO_ECP_DP_SECP521R1_ENABLED */
+
+#endif /* MBEDCRYPTO_ECP_NIST_OPTIM */
+
+#if defined(MBEDCRYPTO_ECP_DP_CURVE25519_ENABLED)
+
+/* Size of p255 in terms of mbedcrypto_mpi_uint */
+#define P255_WIDTH ( 255 / 8 / sizeof( mbedcrypto_mpi_uint ) + 1 )
+
+/*
+ * Fast quasi-reduction modulo p255 = 2^255 - 19
+ * Write N as A0 + 2^255 A1, return A0 + 19 * A1
+ */
+static int ecp_mod_p255( mbedcrypto_mpi *N )
+{
+ int ret;
+ size_t i;
+ mbedcrypto_mpi M;
+ mbedcrypto_mpi_uint Mp[P255_WIDTH + 2];
+
+ if( N->n < P255_WIDTH )
+ return( 0 );
+
+ /* M = A1 */
+ M.s = 1;
+ M.n = N->n - ( P255_WIDTH - 1 );
+ if( M.n > P255_WIDTH + 1 )
+ return( MBEDCRYPTO_ERR_ECP_BAD_INPUT_DATA );
+ M.p = Mp;
+ memset( Mp, 0, sizeof Mp );
+ memcpy( Mp, N->p + P255_WIDTH - 1, M.n * sizeof( mbedcrypto_mpi_uint ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_r( &M, 255 % ( 8 * sizeof( mbedcrypto_mpi_uint ) ) ) );
+ M.n++; /* Make room for multiplication by 19 */
+
+ /* N = A0 */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_set_bit( N, 255, 0 ) );
+ for( i = P255_WIDTH; i < N->n; i++ )
+ N->p[i] = 0;
+
+ /* N = A0 + 19 * A1 */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_int( &M, &M, 19 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_abs( N, N, &M ) );
+
+cleanup:
+ return( ret );
+}
+#endif /* MBEDCRYPTO_ECP_DP_CURVE25519_ENABLED */
+
+#if defined(MBEDCRYPTO_ECP_DP_CURVE448_ENABLED)
+
+/* Size of p448 in terms of mbedcrypto_mpi_uint */
+#define P448_WIDTH ( 448 / 8 / sizeof( mbedcrypto_mpi_uint ) )
+
+/* Number of limbs fully occupied by 2^224 (max), and limbs used by it (min) */
+#define DIV_ROUND_UP( X, Y ) ( ( ( X ) + ( Y ) - 1 ) / ( Y ) )
+#define P224_WIDTH_MIN ( 28 / sizeof( mbedcrypto_mpi_uint ) )
+#define P224_WIDTH_MAX DIV_ROUND_UP( 28, sizeof( mbedcrypto_mpi_uint ) )
+#define P224_UNUSED_BITS ( ( P224_WIDTH_MAX * sizeof( mbedcrypto_mpi_uint ) * 8 ) - 224 )
+
+/*
+ * Fast quasi-reduction modulo p448 = 2^448 - 2^224 - 1
+ * Write N as A0 + 2^448 A1 and A1 as B0 + 2^224 B1, and return
+ * A0 + A1 + B1 + (B0 + B1) * 2^224. This is different to the reference
+ * implementation of Curve448, which uses its own special 56-bit limbs rather
+ * than a generic bignum library. We could squeeze some extra speed out on
+ * 32-bit machines by splitting N up into 32-bit limbs and doing the
+ * arithmetic using the limbs directly as we do for the NIST primes above,
+ * but for 64-bit targets it should use half the number of operations if we do
+ * the reduction with 224-bit limbs, since mpi_add_mpi will then use 64-bit adds.
+ */
+static int ecp_mod_p448( mbedcrypto_mpi *N )
+{
+ int ret;
+ size_t i;
+ mbedcrypto_mpi M, Q;
+ mbedcrypto_mpi_uint Mp[P448_WIDTH + 1], Qp[P448_WIDTH];
+
+ if( N->n <= P448_WIDTH )
+ return( 0 );
+
+ /* M = A1 */
+ M.s = 1;
+ M.n = N->n - ( P448_WIDTH );
+ if( M.n > P448_WIDTH )
+ /* Shouldn't be called with N larger than 2^896! */
+ return( MBEDCRYPTO_ERR_ECP_BAD_INPUT_DATA );
+ M.p = Mp;
+ memset( Mp, 0, sizeof( Mp ) );
+ memcpy( Mp, N->p + P448_WIDTH, M.n * sizeof( mbedcrypto_mpi_uint ) );
+
+ /* N = A0 */
+ for( i = P448_WIDTH; i < N->n; i++ )
+ N->p[i] = 0;
+
+ /* N += A1 */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_mpi( N, N, &M ) );
+
+ /* Q = B1, N += B1 */
+ Q = M;
+ Q.p = Qp;
+ memcpy( Qp, Mp, sizeof( Qp ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_r( &Q, 224 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_mpi( N, N, &Q ) );
+
+ /* M = (B0 + B1) * 2^224, N += M */
+ if( sizeof( mbedcrypto_mpi_uint ) > 4 )
+ Mp[P224_WIDTH_MIN] &= ( (mbedcrypto_mpi_uint)-1 ) >> ( P224_UNUSED_BITS );
+ for( i = P224_WIDTH_MAX; i < M.n; ++i )
+ Mp[i] = 0;
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_mpi( &M, &M, &Q ) );
+ M.n = P448_WIDTH + 1; /* Make room for shifted carry bit from the addition */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_l( &M, 224 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_mpi( N, N, &M ) );
+
+cleanup:
+ return( ret );
+}
+#endif /* MBEDCRYPTO_ECP_DP_CURVE448_ENABLED */
+
+#if defined(MBEDCRYPTO_ECP_DP_SECP192K1_ENABLED) || \
+ defined(MBEDCRYPTO_ECP_DP_SECP224K1_ENABLED) || \
+ defined(MBEDCRYPTO_ECP_DP_SECP256K1_ENABLED)
+/*
+ * Fast quasi-reduction modulo P = 2^s - R,
+ * with R about 33 bits, used by the Koblitz curves.
+ *
+ * Write N as A0 + 2^224 A1, return A0 + R * A1.
+ * Actually do two passes, since R is big.
+ */
+#define P_KOBLITZ_MAX ( 256 / 8 / sizeof( mbedcrypto_mpi_uint ) ) // Max limbs in P
+#define P_KOBLITZ_R ( 8 / sizeof( mbedcrypto_mpi_uint ) ) // Limbs in R
+static inline int ecp_mod_koblitz( mbedcrypto_mpi *N, mbedcrypto_mpi_uint *Rp, size_t p_limbs,
+ size_t adjust, size_t shift, mbedcrypto_mpi_uint mask )
+{
+ int ret;
+ size_t i;
+ mbedcrypto_mpi M, R;
+ mbedcrypto_mpi_uint Mp[P_KOBLITZ_MAX + P_KOBLITZ_R + 1];
+
+ if( N->n < p_limbs )
+ return( 0 );
+
+ /* Init R */
+ R.s = 1;
+ R.p = Rp;
+ R.n = P_KOBLITZ_R;
+
+ /* Common setup for M */
+ M.s = 1;
+ M.p = Mp;
+
+ /* M = A1 */
+ M.n = N->n - ( p_limbs - adjust );
+ if( M.n > p_limbs + adjust )
+ M.n = p_limbs + adjust;
+ memset( Mp, 0, sizeof Mp );
+ memcpy( Mp, N->p + p_limbs - adjust, M.n * sizeof( mbedcrypto_mpi_uint ) );
+ if( shift != 0 )
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_r( &M, shift ) );
+ M.n += R.n; /* Make room for multiplication by R */
+
+ /* N = A0 */
+ if( mask != 0 )
+ N->p[p_limbs - 1] &= mask;
+ for( i = p_limbs; i < N->n; i++ )
+ N->p[i] = 0;
+
+ /* N = A0 + R * A1 */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &M, &M, &R ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_abs( N, N, &M ) );
+
+ /* Second pass */
+
+ /* M = A1 */
+ M.n = N->n - ( p_limbs - adjust );
+ if( M.n > p_limbs + adjust )
+ M.n = p_limbs + adjust;
+ memset( Mp, 0, sizeof Mp );
+ memcpy( Mp, N->p + p_limbs - adjust, M.n * sizeof( mbedcrypto_mpi_uint ) );
+ if( shift != 0 )
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_r( &M, shift ) );
+ M.n += R.n; /* Make room for multiplication by R */
+
+ /* N = A0 */
+ if( mask != 0 )
+ N->p[p_limbs - 1] &= mask;
+ for( i = p_limbs; i < N->n; i++ )
+ N->p[i] = 0;
+
+ /* N = A0 + R * A1 */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &M, &M, &R ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_abs( N, N, &M ) );
+
+cleanup:
+ return( ret );
+}
+#endif /* MBEDCRYPTO_ECP_DP_SECP192K1_ENABLED) ||
+ MBEDCRYPTO_ECP_DP_SECP224K1_ENABLED) ||
+ MBEDCRYPTO_ECP_DP_SECP256K1_ENABLED) */
+
+#if defined(MBEDCRYPTO_ECP_DP_SECP192K1_ENABLED)
+/*
+ * Fast quasi-reduction modulo p192k1 = 2^192 - R,
+ * with R = 2^32 + 2^12 + 2^8 + 2^7 + 2^6 + 2^3 + 1 = 0x0100001119
+ */
+static int ecp_mod_p192k1( mbedcrypto_mpi *N )
+{
+ static mbedcrypto_mpi_uint Rp[] = {
+ BYTES_TO_T_UINT_8( 0xC9, 0x11, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 ) };
+
+ return( ecp_mod_koblitz( N, Rp, 192 / 8 / sizeof( mbedcrypto_mpi_uint ), 0, 0, 0 ) );
+}
+#endif /* MBEDCRYPTO_ECP_DP_SECP192K1_ENABLED */
+
+#if defined(MBEDCRYPTO_ECP_DP_SECP224K1_ENABLED)
+/*
+ * Fast quasi-reduction modulo p224k1 = 2^224 - R,
+ * with R = 2^32 + 2^12 + 2^11 + 2^9 + 2^7 + 2^4 + 2 + 1 = 0x0100001A93
+ */
+static int ecp_mod_p224k1( mbedcrypto_mpi *N )
+{
+ static mbedcrypto_mpi_uint Rp[] = {
+ BYTES_TO_T_UINT_8( 0x93, 0x1A, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 ) };
+
+#if defined(MBEDCRYPTO_HAVE_INT64)
+ return( ecp_mod_koblitz( N, Rp, 4, 1, 32, 0xFFFFFFFF ) );
+#else
+ return( ecp_mod_koblitz( N, Rp, 224 / 8 / sizeof( mbedcrypto_mpi_uint ), 0, 0, 0 ) );
+#endif
+}
+
+#endif /* MBEDCRYPTO_ECP_DP_SECP224K1_ENABLED */
+
+#if defined(MBEDCRYPTO_ECP_DP_SECP256K1_ENABLED)
+/*
+ * Fast quasi-reduction modulo p256k1 = 2^256 - R,
+ * with R = 2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1 = 0x01000003D1
+ */
+static int ecp_mod_p256k1( mbedcrypto_mpi *N )
+{
+ static mbedcrypto_mpi_uint Rp[] = {
+ BYTES_TO_T_UINT_8( 0xD1, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 ) };
+ return( ecp_mod_koblitz( N, Rp, 256 / 8 / sizeof( mbedcrypto_mpi_uint ), 0, 0, 0 ) );
+}
+#endif /* MBEDCRYPTO_ECP_DP_SECP256K1_ENABLED */
+
+#endif /* !MBEDCRYPTO_ECP_ALT */
+
+#endif /* MBEDCRYPTO_ECP_C */
diff --git a/library/entropy.c b/library/entropy.c
new file mode 100644
index 0000000..239d999
--- /dev/null
+++ b/library/entropy.c
@@ -0,0 +1,721 @@
+/*
+ * Entropy accumulator implementation
+ *
+ * Copyright (C) 2006-2016, 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 Crypto (https://tls.mbed.org)
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_ENTROPY_C)
+
+#if defined(MBEDCRYPTO_TEST_NULL_ENTROPY)
+#warning "**** WARNING! MBEDCRYPTO_TEST_NULL_ENTROPY defined! "
+#warning "**** THIS BUILD HAS NO DEFINED ENTROPY SOURCES "
+#warning "**** THIS BUILD IS *NOT* SUITABLE FOR PRODUCTION USE "
+#endif
+
+#include "mbedcrypto/entropy.h"
+#include "mbedcrypto/entropy_poll.h"
+#include "mbedcrypto/platform_util.h"
+
+#include <string.h>
+
+#if defined(MBEDCRYPTO_FS_IO)
+#include <stdio.h>
+#endif
+
+#if defined(MBEDCRYPTO_ENTROPY_NV_SEED)
+#include "mbedcrypto/platform.h"
+#endif
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#include <stdio.h>
+#define mbedcrypto_printf printf
+#endif /* MBEDCRYPTO_PLATFORM_C */
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#if defined(MBEDCRYPTO_HAVEGE_C)
+#include "mbedcrypto/havege.h"
+#endif
+
+#define ENTROPY_MAX_LOOP 256 /**< Maximum amount to loop before error */
+
+void mbedcrypto_entropy_init( mbedcrypto_entropy_context *ctx )
+{
+ ctx->source_count = 0;
+ memset( ctx->source, 0, sizeof( ctx->source ) );
+
+#if defined(MBEDCRYPTO_THREADING_C)
+ mbedcrypto_mutex_init( &ctx->mutex );
+#endif
+
+ ctx->accumulator_started = 0;
+#if defined(MBEDCRYPTO_ENTROPY_SHA512_ACCUMULATOR)
+ mbedcrypto_sha512_init( &ctx->accumulator );
+#else
+ mbedcrypto_sha256_init( &ctx->accumulator );
+#endif
+#if defined(MBEDCRYPTO_HAVEGE_C)
+ mbedcrypto_havege_init( &ctx->havege_data );
+#endif
+
+ /* Reminder: Update ENTROPY_HAVE_STRONG in the test files
+ * when adding more strong entropy sources here. */
+
+#if defined(MBEDCRYPTO_TEST_NULL_ENTROPY)
+ mbedcrypto_entropy_add_source( ctx, mbedcrypto_null_entropy_poll, NULL,
+ 1, MBEDCRYPTO_ENTROPY_SOURCE_STRONG );
+#endif
+
+#if !defined(MBEDCRYPTO_NO_DEFAULT_ENTROPY_SOURCES)
+#if !defined(MBEDCRYPTO_NO_PLATFORM_ENTROPY)
+ mbedcrypto_entropy_add_source( ctx, mbedcrypto_platform_entropy_poll, NULL,
+ MBEDCRYPTO_ENTROPY_MIN_PLATFORM,
+ MBEDCRYPTO_ENTROPY_SOURCE_STRONG );
+#endif
+#if defined(MBEDCRYPTO_TIMING_C)
+ mbedcrypto_entropy_add_source( ctx, mbedcrypto_hardclock_poll, NULL,
+ MBEDCRYPTO_ENTROPY_MIN_HARDCLOCK,
+ MBEDCRYPTO_ENTROPY_SOURCE_WEAK );
+#endif
+#if defined(MBEDCRYPTO_HAVEGE_C)
+ mbedcrypto_entropy_add_source( ctx, mbedcrypto_havege_poll, &ctx->havege_data,
+ MBEDCRYPTO_ENTROPY_MIN_HAVEGE,
+ MBEDCRYPTO_ENTROPY_SOURCE_STRONG );
+#endif
+#if defined(MBEDCRYPTO_ENTROPY_HARDWARE_ALT)
+ mbedcrypto_entropy_add_source( ctx, mbedcrypto_hardware_poll, NULL,
+ MBEDCRYPTO_ENTROPY_MIN_HARDWARE,
+ MBEDCRYPTO_ENTROPY_SOURCE_STRONG );
+#endif
+#if defined(MBEDCRYPTO_ENTROPY_NV_SEED)
+ mbedcrypto_entropy_add_source( ctx, mbedcrypto_nv_seed_poll, NULL,
+ MBEDCRYPTO_ENTROPY_BLOCK_SIZE,
+ MBEDCRYPTO_ENTROPY_SOURCE_STRONG );
+ ctx->initial_entropy_run = 0;
+#endif
+#endif /* MBEDCRYPTO_NO_DEFAULT_ENTROPY_SOURCES */
+}
+
+void mbedcrypto_entropy_free( mbedcrypto_entropy_context *ctx )
+{
+#if defined(MBEDCRYPTO_HAVEGE_C)
+ mbedcrypto_havege_free( &ctx->havege_data );
+#endif
+#if defined(MBEDCRYPTO_THREADING_C)
+ mbedcrypto_mutex_free( &ctx->mutex );
+#endif
+#if defined(MBEDCRYPTO_ENTROPY_SHA512_ACCUMULATOR)
+ mbedcrypto_sha512_free( &ctx->accumulator );
+#else
+ mbedcrypto_sha256_free( &ctx->accumulator );
+#endif
+#if defined(MBEDCRYPTO_ENTROPY_NV_SEED)
+ ctx->initial_entropy_run = 0;
+#endif
+ ctx->source_count = 0;
+ mbedcrypto_platform_zeroize( ctx->source, sizeof( ctx->source ) );
+ ctx->accumulator_started = 0;
+}
+
+int mbedcrypto_entropy_add_source( mbedcrypto_entropy_context *ctx,
+ mbedcrypto_entropy_f_source_ptr f_source, void *p_source,
+ size_t threshold, int strong )
+{
+ int idx, ret = 0;
+
+#if defined(MBEDCRYPTO_THREADING_C)
+ if( ( ret = mbedcrypto_mutex_lock( &ctx->mutex ) ) != 0 )
+ return( ret );
+#endif
+
+ idx = ctx->source_count;
+ if( idx >= MBEDCRYPTO_ENTROPY_MAX_SOURCES )
+ {
+ ret = MBEDCRYPTO_ERR_ENTROPY_MAX_SOURCES;
+ goto exit;
+ }
+
+ ctx->source[idx].f_source = f_source;
+ ctx->source[idx].p_source = p_source;
+ ctx->source[idx].threshold = threshold;
+ ctx->source[idx].strong = strong;
+
+ ctx->source_count++;
+
+exit:
+#if defined(MBEDCRYPTO_THREADING_C)
+ if( mbedcrypto_mutex_unlock( &ctx->mutex ) != 0 )
+ return( MBEDCRYPTO_ERR_THREADING_MUTEX_ERROR );
+#endif
+
+ return( ret );
+}
+
+/*
+ * Entropy accumulator update
+ */
+static int entropy_update( mbedcrypto_entropy_context *ctx, unsigned char source_id,
+ const unsigned char *data, size_t len )
+{
+ unsigned char header[2];
+ unsigned char tmp[MBEDCRYPTO_ENTROPY_BLOCK_SIZE];
+ size_t use_len = len;
+ const unsigned char *p = data;
+ int ret = 0;
+
+ if( use_len > MBEDCRYPTO_ENTROPY_BLOCK_SIZE )
+ {
+#if defined(MBEDCRYPTO_ENTROPY_SHA512_ACCUMULATOR)
+ if( ( ret = mbedcrypto_sha512_ret( data, len, tmp, 0 ) ) != 0 )
+ goto cleanup;
+#else
+ if( ( ret = mbedcrypto_sha256_ret( data, len, tmp, 0 ) ) != 0 )
+ goto cleanup;
+#endif
+ p = tmp;
+ use_len = MBEDCRYPTO_ENTROPY_BLOCK_SIZE;
+ }
+
+ header[0] = source_id;
+ header[1] = use_len & 0xFF;
+
+ /*
+ * Start the accumulator if this has not already happened. Note that
+ * it is sufficient to start the accumulator here only because all calls to
+ * gather entropy eventually execute this code.
+ */
+#if defined(MBEDCRYPTO_ENTROPY_SHA512_ACCUMULATOR)
+ if( ctx->accumulator_started == 0 &&
+ ( ret = mbedcrypto_sha512_starts_ret( &ctx->accumulator, 0 ) ) != 0 )
+ goto cleanup;
+ else
+ ctx->accumulator_started = 1;
+ if( ( ret = mbedcrypto_sha512_update_ret( &ctx->accumulator, header, 2 ) ) != 0 )
+ goto cleanup;
+ ret = mbedcrypto_sha512_update_ret( &ctx->accumulator, p, use_len );
+#else
+ if( ctx->accumulator_started == 0 &&
+ ( ret = mbedcrypto_sha256_starts_ret( &ctx->accumulator, 0 ) ) != 0 )
+ goto cleanup;
+ else
+ ctx->accumulator_started = 1;
+ if( ( ret = mbedcrypto_sha256_update_ret( &ctx->accumulator, header, 2 ) ) != 0 )
+ goto cleanup;
+ ret = mbedcrypto_sha256_update_ret( &ctx->accumulator, p, use_len );
+#endif
+
+cleanup:
+ mbedcrypto_platform_zeroize( tmp, sizeof( tmp ) );
+
+ return( ret );
+}
+
+int mbedcrypto_entropy_update_manual( mbedcrypto_entropy_context *ctx,
+ const unsigned char *data, size_t len )
+{
+ int ret;
+
+#if defined(MBEDCRYPTO_THREADING_C)
+ if( ( ret = mbedcrypto_mutex_lock( &ctx->mutex ) ) != 0 )
+ return( ret );
+#endif
+
+ ret = entropy_update( ctx, MBEDCRYPTO_ENTROPY_SOURCE_MANUAL, data, len );
+
+#if defined(MBEDCRYPTO_THREADING_C)
+ if( mbedcrypto_mutex_unlock( &ctx->mutex ) != 0 )
+ return( MBEDCRYPTO_ERR_THREADING_MUTEX_ERROR );
+#endif
+
+ return( ret );
+}
+
+/*
+ * Run through the different sources to add entropy to our accumulator
+ */
+static int entropy_gather_internal( mbedcrypto_entropy_context *ctx )
+{
+ int ret, i, have_one_strong = 0;
+ unsigned char buf[MBEDCRYPTO_ENTROPY_MAX_GATHER];
+ size_t olen;
+
+ if( ctx->source_count == 0 )
+ return( MBEDCRYPTO_ERR_ENTROPY_NO_SOURCES_DEFINED );
+
+ /*
+ * Run through our entropy sources
+ */
+ for( i = 0; i < ctx->source_count; i++ )
+ {
+ if( ctx->source[i].strong == MBEDCRYPTO_ENTROPY_SOURCE_STRONG )
+ have_one_strong = 1;
+
+ olen = 0;
+ if( ( ret = ctx->source[i].f_source( ctx->source[i].p_source,
+ buf, MBEDCRYPTO_ENTROPY_MAX_GATHER, &olen ) ) != 0 )
+ {
+ goto cleanup;
+ }
+
+ /*
+ * Add if we actually gathered something
+ */
+ if( olen > 0 )
+ {
+ if( ( ret = entropy_update( ctx, (unsigned char) i,
+ buf, olen ) ) != 0 )
+ return( ret );
+ ctx->source[i].size += olen;
+ }
+ }
+
+ if( have_one_strong == 0 )
+ ret = MBEDCRYPTO_ERR_ENTROPY_NO_STRONG_SOURCE;
+
+cleanup:
+ mbedcrypto_platform_zeroize( buf, sizeof( buf ) );
+
+ return( ret );
+}
+
+/*
+ * Thread-safe wrapper for entropy_gather_internal()
+ */
+int mbedcrypto_entropy_gather( mbedcrypto_entropy_context *ctx )
+{
+ int ret;
+
+#if defined(MBEDCRYPTO_THREADING_C)
+ if( ( ret = mbedcrypto_mutex_lock( &ctx->mutex ) ) != 0 )
+ return( ret );
+#endif
+
+ ret = entropy_gather_internal( ctx );
+
+#if defined(MBEDCRYPTO_THREADING_C)
+ if( mbedcrypto_mutex_unlock( &ctx->mutex ) != 0 )
+ return( MBEDCRYPTO_ERR_THREADING_MUTEX_ERROR );
+#endif
+
+ return( ret );
+}
+
+int mbedcrypto_entropy_func( void *data, unsigned char *output, size_t len )
+{
+ int ret, count = 0, i, done;
+ mbedcrypto_entropy_context *ctx = (mbedcrypto_entropy_context *) data;
+ unsigned char buf[MBEDCRYPTO_ENTROPY_BLOCK_SIZE];
+
+ if( len > MBEDCRYPTO_ENTROPY_BLOCK_SIZE )
+ return( MBEDCRYPTO_ERR_ENTROPY_SOURCE_FAILED );
+
+#if defined(MBEDCRYPTO_ENTROPY_NV_SEED)
+ /* Update the NV entropy seed before generating any entropy for outside
+ * use.
+ */
+ if( ctx->initial_entropy_run == 0 )
+ {
+ ctx->initial_entropy_run = 1;
+ if( ( ret = mbedcrypto_entropy_update_nv_seed( ctx ) ) != 0 )
+ return( ret );
+ }
+#endif
+
+#if defined(MBEDCRYPTO_THREADING_C)
+ if( ( ret = mbedcrypto_mutex_lock( &ctx->mutex ) ) != 0 )
+ return( ret );
+#endif
+
+ /*
+ * Always gather extra entropy before a call
+ */
+ do
+ {
+ if( count++ > ENTROPY_MAX_LOOP )
+ {
+ ret = MBEDCRYPTO_ERR_ENTROPY_SOURCE_FAILED;
+ goto exit;
+ }
+
+ if( ( ret = entropy_gather_internal( ctx ) ) != 0 )
+ goto exit;
+
+ done = 1;
+ for( i = 0; i < ctx->source_count; i++ )
+ if( ctx->source[i].size < ctx->source[i].threshold )
+ done = 0;
+ }
+ while( ! done );
+
+ memset( buf, 0, MBEDCRYPTO_ENTROPY_BLOCK_SIZE );
+
+#if defined(MBEDCRYPTO_ENTROPY_SHA512_ACCUMULATOR)
+ /*
+ * Note that at this stage it is assumed that the accumulator was started
+ * in a previous call to entropy_update(). If this is not guaranteed, the
+ * code below will fail.
+ */
+ if( ( ret = mbedcrypto_sha512_finish_ret( &ctx->accumulator, buf ) ) != 0 )
+ goto exit;
+
+ /*
+ * Reset accumulator and counters and recycle existing entropy
+ */
+ mbedcrypto_sha512_free( &ctx->accumulator );
+ mbedcrypto_sha512_init( &ctx->accumulator );
+ if( ( ret = mbedcrypto_sha512_starts_ret( &ctx->accumulator, 0 ) ) != 0 )
+ goto exit;
+ if( ( ret = mbedcrypto_sha512_update_ret( &ctx->accumulator, buf,
+ MBEDCRYPTO_ENTROPY_BLOCK_SIZE ) ) != 0 )
+ goto exit;
+
+ /*
+ * Perform second SHA-512 on entropy
+ */
+ if( ( ret = mbedcrypto_sha512_ret( buf, MBEDCRYPTO_ENTROPY_BLOCK_SIZE,
+ buf, 0 ) ) != 0 )
+ goto exit;
+#else /* MBEDCRYPTO_ENTROPY_SHA512_ACCUMULATOR */
+ if( ( ret = mbedcrypto_sha256_finish_ret( &ctx->accumulator, buf ) ) != 0 )
+ goto exit;
+
+ /*
+ * Reset accumulator and counters and recycle existing entropy
+ */
+ mbedcrypto_sha256_free( &ctx->accumulator );
+ mbedcrypto_sha256_init( &ctx->accumulator );
+ if( ( ret = mbedcrypto_sha256_starts_ret( &ctx->accumulator, 0 ) ) != 0 )
+ goto exit;
+ if( ( ret = mbedcrypto_sha256_update_ret( &ctx->accumulator, buf,
+ MBEDCRYPTO_ENTROPY_BLOCK_SIZE ) ) != 0 )
+ goto exit;
+
+ /*
+ * Perform second SHA-256 on entropy
+ */
+ if( ( ret = mbedcrypto_sha256_ret( buf, MBEDCRYPTO_ENTROPY_BLOCK_SIZE,
+ buf, 0 ) ) != 0 )
+ goto exit;
+#endif /* MBEDCRYPTO_ENTROPY_SHA512_ACCUMULATOR */
+
+ for( i = 0; i < ctx->source_count; i++ )
+ ctx->source[i].size = 0;
+
+ memcpy( output, buf, len );
+
+ ret = 0;
+
+exit:
+ mbedcrypto_platform_zeroize( buf, sizeof( buf ) );
+
+#if defined(MBEDCRYPTO_THREADING_C)
+ if( mbedcrypto_mutex_unlock( &ctx->mutex ) != 0 )
+ return( MBEDCRYPTO_ERR_THREADING_MUTEX_ERROR );
+#endif
+
+ return( ret );
+}
+
+#if defined(MBEDCRYPTO_ENTROPY_NV_SEED)
+int mbedcrypto_entropy_update_nv_seed( mbedcrypto_entropy_context *ctx )
+{
+ int ret = MBEDCRYPTO_ERR_ENTROPY_FILE_IO_ERROR;
+ unsigned char buf[MBEDCRYPTO_ENTROPY_BLOCK_SIZE];
+
+ /* Read new seed and write it to NV */
+ if( ( ret = mbedcrypto_entropy_func( ctx, buf, MBEDCRYPTO_ENTROPY_BLOCK_SIZE ) ) != 0 )
+ return( ret );
+
+ if( mbedcrypto_nv_seed_write( buf, MBEDCRYPTO_ENTROPY_BLOCK_SIZE ) < 0 )
+ return( MBEDCRYPTO_ERR_ENTROPY_FILE_IO_ERROR );
+
+ /* Manually update the remaining stream with a separator value to diverge */
+ memset( buf, 0, MBEDCRYPTO_ENTROPY_BLOCK_SIZE );
+ ret = mbedcrypto_entropy_update_manual( ctx, buf, MBEDCRYPTO_ENTROPY_BLOCK_SIZE );
+
+ return( ret );
+}
+#endif /* MBEDCRYPTO_ENTROPY_NV_SEED */
+
+#if defined(MBEDCRYPTO_FS_IO)
+int mbedcrypto_entropy_write_seed_file( mbedcrypto_entropy_context *ctx, const char *path )
+{
+ int ret = MBEDCRYPTO_ERR_ENTROPY_FILE_IO_ERROR;
+ FILE *f;
+ unsigned char buf[MBEDCRYPTO_ENTROPY_BLOCK_SIZE];
+
+ if( ( f = fopen( path, "wb" ) ) == NULL )
+ return( MBEDCRYPTO_ERR_ENTROPY_FILE_IO_ERROR );
+
+ if( ( ret = mbedcrypto_entropy_func( ctx, buf, MBEDCRYPTO_ENTROPY_BLOCK_SIZE ) ) != 0 )
+ goto exit;
+
+ if( fwrite( buf, 1, MBEDCRYPTO_ENTROPY_BLOCK_SIZE, f ) != MBEDCRYPTO_ENTROPY_BLOCK_SIZE )
+ {
+ ret = MBEDCRYPTO_ERR_ENTROPY_FILE_IO_ERROR;
+ goto exit;
+ }
+
+ ret = 0;
+
+exit:
+ mbedcrypto_platform_zeroize( buf, sizeof( buf ) );
+
+ fclose( f );
+ return( ret );
+}
+
+int mbedcrypto_entropy_update_seed_file( mbedcrypto_entropy_context *ctx, const char *path )
+{
+ int ret = 0;
+ FILE *f;
+ size_t n;
+ unsigned char buf[ MBEDCRYPTO_ENTROPY_MAX_SEED_SIZE ];
+
+ if( ( f = fopen( path, "rb" ) ) == NULL )
+ return( MBEDCRYPTO_ERR_ENTROPY_FILE_IO_ERROR );
+
+ fseek( f, 0, SEEK_END );
+ n = (size_t) ftell( f );
+ fseek( f, 0, SEEK_SET );
+
+ if( n > MBEDCRYPTO_ENTROPY_MAX_SEED_SIZE )
+ n = MBEDCRYPTO_ENTROPY_MAX_SEED_SIZE;
+
+ if( fread( buf, 1, n, f ) != n )
+ ret = MBEDCRYPTO_ERR_ENTROPY_FILE_IO_ERROR;
+ else
+ ret = mbedcrypto_entropy_update_manual( ctx, buf, n );
+
+ fclose( f );
+
+ mbedcrypto_platform_zeroize( buf, sizeof( buf ) );
+
+ if( ret != 0 )
+ return( ret );
+
+ return( mbedcrypto_entropy_write_seed_file( ctx, path ) );
+}
+#endif /* MBEDCRYPTO_FS_IO */
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+#if !defined(MBEDCRYPTO_TEST_NULL_ENTROPY)
+/*
+ * Dummy source function
+ */
+static int entropy_dummy_source( void *data, unsigned char *output,
+ size_t len, size_t *olen )
+{
+ ((void) data);
+
+ memset( output, 0x2a, len );
+ *olen = len;
+
+ return( 0 );
+}
+#endif /* !MBEDCRYPTO_TEST_NULL_ENTROPY */
+
+#if defined(MBEDCRYPTO_ENTROPY_HARDWARE_ALT)
+
+static int mbedcrypto_entropy_source_self_test_gather( unsigned char *buf, size_t buf_len )
+{
+ int ret = 0;
+ size_t entropy_len = 0;
+ size_t olen = 0;
+ size_t attempts = buf_len;
+
+ while( attempts > 0 && entropy_len < buf_len )
+ {
+ if( ( ret = mbedcrypto_hardware_poll( NULL, buf + entropy_len,
+ buf_len - entropy_len, &olen ) ) != 0 )
+ return( ret );
+
+ entropy_len += olen;
+ attempts--;
+ }
+
+ if( entropy_len < buf_len )
+ {
+ ret = 1;
+ }
+
+ return( ret );
+}
+
+
+static int mbedcrypto_entropy_source_self_test_check_bits( const unsigned char *buf,
+ size_t buf_len )
+{
+ unsigned char set= 0xFF;
+ unsigned char unset = 0x00;
+ size_t i;
+
+ for( i = 0; i < buf_len; i++ )
+ {
+ set &= buf[i];
+ unset |= buf[i];
+ }
+
+ return( set == 0xFF || unset == 0x00 );
+}
+
+/*
+ * A test to ensure hat the entropy sources are functioning correctly
+ * and there is no obvious failure. The test performs the following checks:
+ * - The entropy source is not providing only 0s (all bits unset) or 1s (all
+ * bits set).
+ * - The entropy source is not providing values in a pattern. Because the
+ * hardware could be providing data in an arbitrary length, this check polls
+ * the hardware entropy source twice and compares the result to ensure they
+ * are not equal.
+ * - The error code returned by the entropy source is not an error.
+ */
+int mbedcrypto_entropy_source_self_test( int verbose )
+{
+ int ret = 0;
+ unsigned char buf0[2 * sizeof( unsigned long long int )];
+ unsigned char buf1[2 * sizeof( unsigned long long int )];
+
+ if( verbose != 0 )
+ mbedcrypto_printf( " ENTROPY_BIAS test: " );
+
+ memset( buf0, 0x00, sizeof( buf0 ) );
+ memset( buf1, 0x00, sizeof( buf1 ) );
+
+ if( ( ret = mbedcrypto_entropy_source_self_test_gather( buf0, sizeof( buf0 ) ) ) != 0 )
+ goto cleanup;
+ if( ( ret = mbedcrypto_entropy_source_self_test_gather( buf1, sizeof( buf1 ) ) ) != 0 )
+ goto cleanup;
+
+ /* Make sure that the returned values are not all 0 or 1 */
+ if( ( ret = mbedcrypto_entropy_source_self_test_check_bits( buf0, sizeof( buf0 ) ) ) != 0 )
+ goto cleanup;
+ if( ( ret = mbedcrypto_entropy_source_self_test_check_bits( buf1, sizeof( buf1 ) ) ) != 0 )
+ goto cleanup;
+
+ /* Make sure that the entropy source is not returning values in a
+ * pattern */
+ ret = memcmp( buf0, buf1, sizeof( buf0 ) ) == 0;
+
+cleanup:
+ if( verbose != 0 )
+ {
+ if( ret != 0 )
+ mbedcrypto_printf( "failed\n" );
+ else
+ mbedcrypto_printf( "passed\n" );
+
+ mbedcrypto_printf( "\n" );
+ }
+
+ return( ret != 0 );
+}
+
+#endif /* MBEDCRYPTO_ENTROPY_HARDWARE_ALT */
+
+/*
+ * The actual entropy quality is hard to test, but we can at least
+ * test that the functions don't cause errors and write the correct
+ * amount of data to buffers.
+ */
+int mbedcrypto_entropy_self_test( int verbose )
+{
+ int ret = 1;
+#if !defined(MBEDCRYPTO_TEST_NULL_ENTROPY)
+ mbedcrypto_entropy_context ctx;
+ unsigned char buf[MBEDCRYPTO_ENTROPY_BLOCK_SIZE] = { 0 };
+ unsigned char acc[MBEDCRYPTO_ENTROPY_BLOCK_SIZE] = { 0 };
+ size_t i, j;
+#endif /* !MBEDCRYPTO_TEST_NULL_ENTROPY */
+
+ if( verbose != 0 )
+ mbedcrypto_printf( " ENTROPY test: " );
+
+#if !defined(MBEDCRYPTO_TEST_NULL_ENTROPY)
+ mbedcrypto_entropy_init( &ctx );
+
+ /* First do a gather to make sure we have default sources */
+ if( ( ret = mbedcrypto_entropy_gather( &ctx ) ) != 0 )
+ goto cleanup;
+
+ ret = mbedcrypto_entropy_add_source( &ctx, entropy_dummy_source, NULL, 16,
+ MBEDCRYPTO_ENTROPY_SOURCE_WEAK );
+ if( ret != 0 )
+ goto cleanup;
+
+ if( ( ret = mbedcrypto_entropy_update_manual( &ctx, buf, sizeof buf ) ) != 0 )
+ goto cleanup;
+
+ /*
+ * To test that mbedcrypto_entropy_func writes correct number of bytes:
+ * - use the whole buffer and rely on ASan to detect overruns
+ * - collect entropy 8 times and OR the result in an accumulator:
+ * any byte should then be 0 with probably 2^(-64), so requiring
+ * each of the 32 or 64 bytes to be non-zero has a false failure rate
+ * of at most 2^(-58) which is acceptable.
+ */
+ for( i = 0; i < 8; i++ )
+ {
+ if( ( ret = mbedcrypto_entropy_func( &ctx, buf, sizeof( buf ) ) ) != 0 )
+ goto cleanup;
+
+ for( j = 0; j < sizeof( buf ); j++ )
+ acc[j] |= buf[j];
+ }
+
+ for( j = 0; j < sizeof( buf ); j++ )
+ {
+ if( acc[j] == 0 )
+ {
+ ret = 1;
+ goto cleanup;
+ }
+ }
+
+#if defined(MBEDCRYPTO_ENTROPY_HARDWARE_ALT)
+ if( ( ret = mbedcrypto_entropy_source_self_test( 0 ) ) != 0 )
+ goto cleanup;
+#endif
+
+cleanup:
+ mbedcrypto_entropy_free( &ctx );
+#endif /* !MBEDCRYPTO_TEST_NULL_ENTROPY */
+
+ if( verbose != 0 )
+ {
+ if( ret != 0 )
+ mbedcrypto_printf( "failed\n" );
+ else
+ mbedcrypto_printf( "passed\n" );
+
+ mbedcrypto_printf( "\n" );
+ }
+
+ return( ret != 0 );
+}
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#endif /* MBEDCRYPTO_ENTROPY_C */
diff --git a/library/entropy_poll.c b/library/entropy_poll.c
new file mode 100644
index 0000000..4c9f61f
--- /dev/null
+++ b/library/entropy_poll.c
@@ -0,0 +1,269 @@
+/*
+ * Platform-specific and custom entropy polling functions
+ *
+ * Copyright (C) 2006-2016, 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 Crypto (https://tls.mbed.org)
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#include <string.h>
+
+#if defined(MBEDCRYPTO_ENTROPY_C)
+
+#include "mbedcrypto/entropy.h"
+#include "mbedcrypto/entropy_poll.h"
+
+#if defined(MBEDCRYPTO_TIMING_C)
+#include "mbedcrypto/timing.h"
+#endif
+#if defined(MBEDCRYPTO_HAVEGE_C)
+#include "mbedcrypto/havege.h"
+#endif
+#if defined(MBEDCRYPTO_ENTROPY_NV_SEED)
+#include "mbedcrypto/platform.h"
+#endif
+
+#if !defined(MBEDCRYPTO_NO_PLATFORM_ENTROPY)
+
+#if !defined(unix) && !defined(__unix__) && !defined(__unix) && \
+ !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__)
+#error "Platform entropy sources only work on Unix and Windows, see MBEDCRYPTO_NO_PLATFORM_ENTROPY in config.h"
+#endif
+
+#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
+
+#if !defined(_WIN32_WINNT)
+#define _WIN32_WINNT 0x0400
+#endif
+#include <windows.h>
+#include <wincrypt.h>
+
+int mbedcrypto_platform_entropy_poll( void *data, unsigned char *output, size_t len,
+ size_t *olen )
+{
+ HCRYPTPROV provider;
+ ((void) data);
+ *olen = 0;
+
+ if( CryptAcquireContext( &provider, NULL, NULL,
+ PROV_RSA_FULL, CRYPT_VERIFYCONTEXT ) == FALSE )
+ {
+ return( MBEDCRYPTO_ERR_ENTROPY_SOURCE_FAILED );
+ }
+
+ if( CryptGenRandom( provider, (DWORD) len, output ) == FALSE )
+ {
+ CryptReleaseContext( provider, 0 );
+ return( MBEDCRYPTO_ERR_ENTROPY_SOURCE_FAILED );
+ }
+
+ CryptReleaseContext( provider, 0 );
+ *olen = len;
+
+ return( 0 );
+}
+#else /* _WIN32 && !EFIX64 && !EFI32 */
+
+/*
+ * Test for Linux getrandom() support.
+ * Since there is no wrapper in the libc yet, use the generic syscall wrapper
+ * available in GNU libc and compatible libc's (eg uClibc).
+ */
+#if defined(__linux__) && defined(__GLIBC__)
+#include <unistd.h>
+#include <sys/syscall.h>
+#if defined(SYS_getrandom)
+#define HAVE_GETRANDOM
+
+static int getrandom_wrapper( void *buf, size_t buflen, unsigned int flags )
+{
+ /* MemSan cannot understand that the syscall writes to the buffer */
+#if defined(__has_feature)
+#if __has_feature(memory_sanitizer)
+ memset( buf, 0, buflen );
+#endif
+#endif
+
+ return( syscall( SYS_getrandom, buf, buflen, flags ) );
+}
+
+#include <sys/utsname.h>
+/* Check if version is at least 3.17.0 */
+static int check_version_3_17_plus( void )
+{
+ int minor;
+ struct utsname un;
+ const char *ver;
+
+ /* Get version information */
+ uname(&un);
+ ver = un.release;
+
+ /* Check major version; assume a single digit */
+ if( ver[0] < '3' || ver[0] > '9' || ver [1] != '.' )
+ return( -1 );
+
+ if( ver[0] - '0' > 3 )
+ return( 0 );
+
+ /* Ok, so now we know major == 3, check minor.
+ * Assume 1 or 2 digits. */
+ if( ver[2] < '0' || ver[2] > '9' )
+ return( -1 );
+
+ minor = ver[2] - '0';
+
+ if( ver[3] >= '0' && ver[3] <= '9' )
+ minor = 10 * minor + ver[3] - '0';
+ else if( ver [3] != '.' )
+ return( -1 );
+
+ if( minor < 17 )
+ return( -1 );
+
+ return( 0 );
+}
+static int has_getrandom = -1;
+#endif /* SYS_getrandom */
+#endif /* __linux__ */
+
+#include <stdio.h>
+
+int mbedcrypto_platform_entropy_poll( void *data,
+ unsigned char *output, size_t len, size_t *olen )
+{
+ FILE *file;
+ size_t read_len;
+ ((void) data);
+
+#if defined(HAVE_GETRANDOM)
+ if( has_getrandom == -1 )
+ has_getrandom = ( check_version_3_17_plus() == 0 );
+
+ if( has_getrandom )
+ {
+ int ret;
+
+ if( ( ret = getrandom_wrapper( output, len, 0 ) ) < 0 )
+ return( MBEDCRYPTO_ERR_ENTROPY_SOURCE_FAILED );
+
+ *olen = ret;
+ return( 0 );
+ }
+#endif /* HAVE_GETRANDOM */
+
+ *olen = 0;
+
+ file = fopen( "/dev/urandom", "rb" );
+ if( file == NULL )
+ return( MBEDCRYPTO_ERR_ENTROPY_SOURCE_FAILED );
+
+ read_len = fread( output, 1, len, file );
+ if( read_len != len )
+ {
+ fclose( file );
+ return( MBEDCRYPTO_ERR_ENTROPY_SOURCE_FAILED );
+ }
+
+ fclose( file );
+ *olen = len;
+
+ return( 0 );
+}
+#endif /* _WIN32 && !EFIX64 && !EFI32 */
+#endif /* !MBEDCRYPTO_NO_PLATFORM_ENTROPY */
+
+#if defined(MBEDCRYPTO_TEST_NULL_ENTROPY)
+int mbedcrypto_null_entropy_poll( void *data,
+ unsigned char *output, size_t len, size_t *olen )
+{
+ ((void) data);
+ ((void) output);
+ *olen = 0;
+
+ if( len < sizeof(unsigned char) )
+ return( 0 );
+
+ *olen = sizeof(unsigned char);
+
+ return( 0 );
+}
+#endif
+
+#if defined(MBEDCRYPTO_TIMING_C)
+int mbedcrypto_hardclock_poll( void *data,
+ unsigned char *output, size_t len, size_t *olen )
+{
+ unsigned long timer = mbedcrypto_timing_hardclock();
+ ((void) data);
+ *olen = 0;
+
+ if( len < sizeof(unsigned long) )
+ return( 0 );
+
+ memcpy( output, &timer, sizeof(unsigned long) );
+ *olen = sizeof(unsigned long);
+
+ return( 0 );
+}
+#endif /* MBEDCRYPTO_TIMING_C */
+
+#if defined(MBEDCRYPTO_HAVEGE_C)
+int mbedcrypto_havege_poll( void *data,
+ unsigned char *output, size_t len, size_t *olen )
+{
+ mbedcrypto_havege_state *hs = (mbedcrypto_havege_state *) data;
+ *olen = 0;
+
+ if( mbedcrypto_havege_random( hs, output, len ) != 0 )
+ return( MBEDCRYPTO_ERR_ENTROPY_SOURCE_FAILED );
+
+ *olen = len;
+
+ return( 0 );
+}
+#endif /* MBEDCRYPTO_HAVEGE_C */
+
+#if defined(MBEDCRYPTO_ENTROPY_NV_SEED)
+int mbedcrypto_nv_seed_poll( void *data,
+ unsigned char *output, size_t len, size_t *olen )
+{
+ unsigned char buf[MBEDCRYPTO_ENTROPY_BLOCK_SIZE];
+ size_t use_len = MBEDCRYPTO_ENTROPY_BLOCK_SIZE;
+ ((void) data);
+
+ memset( buf, 0, MBEDCRYPTO_ENTROPY_BLOCK_SIZE );
+
+ if( mbedcrypto_nv_seed_read( buf, MBEDCRYPTO_ENTROPY_BLOCK_SIZE ) < 0 )
+ return( MBEDCRYPTO_ERR_ENTROPY_SOURCE_FAILED );
+
+ if( len < use_len )
+ use_len = len;
+
+ memcpy( output, buf, use_len );
+ *olen = use_len;
+
+ return( 0 );
+}
+#endif /* MBEDCRYPTO_ENTROPY_NV_SEED */
+
+#endif /* MBEDCRYPTO_ENTROPY_C */
diff --git a/library/gcm.c b/library/gcm.c
new file mode 100644
index 0000000..3481c9f
--- /dev/null
+++ b/library/gcm.c
@@ -0,0 +1,954 @@
+/*
+ * NIST SP800-38D compliant GCM 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 Crypto (https://tls.mbed.org)
+ */
+
+/*
+ * http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf
+ *
+ * See also:
+ * [MGV] http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf
+ *
+ * We use the algorithm described as Shoup's method with 4-bit tables in
+ * [MGV] 4.1, pp. 12-13, to enhance speed without using too much memory.
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_GCM_C)
+
+#include "mbedcrypto/gcm.h"
+#include "mbedcrypto/platform_util.h"
+
+#include <string.h>
+
+#if defined(MBEDCRYPTO_AESNI_C)
+#include "mbedcrypto/aesni.h"
+#endif
+
+#if defined(MBEDCRYPTO_SELF_TEST) && defined(MBEDCRYPTO_AES_C)
+#include "mbedcrypto/aes.h"
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#include <stdio.h>
+#define mbedcrypto_printf printf
+#endif /* MBEDCRYPTO_PLATFORM_C */
+#endif /* MBEDCRYPTO_SELF_TEST && MBEDCRYPTO_AES_C */
+
+#if !defined(MBEDCRYPTO_GCM_ALT)
+
+/*
+ * 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
+
+/*
+ * Initialize a context
+ */
+void mbedcrypto_gcm_init( mbedcrypto_gcm_context *ctx )
+{
+ memset( ctx, 0, sizeof( mbedcrypto_gcm_context ) );
+}
+
+/*
+ * Precompute small multiples of H, that is set
+ * HH[i] || HL[i] = H times i,
+ * where i is seen as a field element as in [MGV], ie high-order bits
+ * correspond to low powers of P. The result is stored in the same way, that
+ * is the high-order bit of HH corresponds to P^0 and the low-order bit of HL
+ * corresponds to P^127.
+ */
+static int gcm_gen_table( mbedcrypto_gcm_context *ctx )
+{
+ int ret, i, j;
+ uint64_t hi, lo;
+ uint64_t vl, vh;
+ unsigned char h[16];
+ size_t olen = 0;
+
+ memset( h, 0, 16 );
+ if( ( ret = mbedcrypto_cipher_update( &ctx->cipher_ctx, h, 16, h, &olen ) ) != 0 )
+ return( ret );
+
+ /* pack h as two 64-bits ints, big-endian */
+ GET_UINT32_BE( hi, h, 0 );
+ GET_UINT32_BE( lo, h, 4 );
+ vh = (uint64_t) hi << 32 | lo;
+
+ GET_UINT32_BE( hi, h, 8 );
+ GET_UINT32_BE( lo, h, 12 );
+ vl = (uint64_t) hi << 32 | lo;
+
+ /* 8 = 1000 corresponds to 1 in GF(2^128) */
+ ctx->HL[8] = vl;
+ ctx->HH[8] = vh;
+
+#if defined(MBEDCRYPTO_AESNI_C) && defined(MBEDCRYPTO_HAVE_X86_64)
+ /* With CLMUL support, we need only h, not the rest of the table */
+ if( mbedcrypto_aesni_has_support( MBEDCRYPTO_AESNI_CLMUL ) )
+ return( 0 );
+#endif
+
+ /* 0 corresponds to 0 in GF(2^128) */
+ ctx->HH[0] = 0;
+ ctx->HL[0] = 0;
+
+ for( i = 4; i > 0; i >>= 1 )
+ {
+ uint32_t T = ( vl & 1 ) * 0xe1000000U;
+ vl = ( vh << 63 ) | ( vl >> 1 );
+ vh = ( vh >> 1 ) ^ ( (uint64_t) T << 32);
+
+ ctx->HL[i] = vl;
+ ctx->HH[i] = vh;
+ }
+
+ for( i = 2; i <= 8; i *= 2 )
+ {
+ uint64_t *HiL = ctx->HL + i, *HiH = ctx->HH + i;
+ vh = *HiH;
+ vl = *HiL;
+ for( j = 1; j < i; j++ )
+ {
+ HiH[j] = vh ^ ctx->HH[j];
+ HiL[j] = vl ^ ctx->HL[j];
+ }
+ }
+
+ return( 0 );
+}
+
+int mbedcrypto_gcm_setkey( mbedcrypto_gcm_context *ctx,
+ mbedcrypto_cipher_id_t cipher,
+ const unsigned char *key,
+ unsigned int keybits )
+{
+ int ret;
+ const mbedcrypto_cipher_info_t *cipher_info;
+
+ cipher_info = mbedcrypto_cipher_info_from_values( cipher, keybits, MBEDCRYPTO_MODE_ECB );
+ if( cipher_info == NULL )
+ return( MBEDCRYPTO_ERR_GCM_BAD_INPUT );
+
+ if( cipher_info->block_size != 16 )
+ return( MBEDCRYPTO_ERR_GCM_BAD_INPUT );
+
+ mbedcrypto_cipher_free( &ctx->cipher_ctx );
+
+ if( ( ret = mbedcrypto_cipher_setup( &ctx->cipher_ctx, cipher_info ) ) != 0 )
+ return( ret );
+
+ if( ( ret = mbedcrypto_cipher_setkey( &ctx->cipher_ctx, key, keybits,
+ MBEDCRYPTO_ENCRYPT ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ if( ( ret = gcm_gen_table( ctx ) ) != 0 )
+ return( ret );
+
+ return( 0 );
+}
+
+/*
+ * Shoup's method for multiplication use this table with
+ * last4[x] = x times P^128
+ * where x and last4[x] are seen as elements of GF(2^128) as in [MGV]
+ */
+static const uint64_t last4[16] =
+{
+ 0x0000, 0x1c20, 0x3840, 0x2460,
+ 0x7080, 0x6ca0, 0x48c0, 0x54e0,
+ 0xe100, 0xfd20, 0xd940, 0xc560,
+ 0x9180, 0x8da0, 0xa9c0, 0xb5e0
+};
+
+/*
+ * Sets output to x times H using the precomputed tables.
+ * x and output are seen as elements of GF(2^128) as in [MGV].
+ */
+static void gcm_mult( mbedcrypto_gcm_context *ctx, const unsigned char x[16],
+ unsigned char output[16] )
+{
+ int i = 0;
+ unsigned char lo, hi, rem;
+ uint64_t zh, zl;
+
+#if defined(MBEDCRYPTO_AESNI_C) && defined(MBEDCRYPTO_HAVE_X86_64)
+ if( mbedcrypto_aesni_has_support( MBEDCRYPTO_AESNI_CLMUL ) ) {
+ unsigned char h[16];
+
+ PUT_UINT32_BE( ctx->HH[8] >> 32, h, 0 );
+ PUT_UINT32_BE( ctx->HH[8], h, 4 );
+ PUT_UINT32_BE( ctx->HL[8] >> 32, h, 8 );
+ PUT_UINT32_BE( ctx->HL[8], h, 12 );
+
+ mbedcrypto_aesni_gcm_mult( output, x, h );
+ return;
+ }
+#endif /* MBEDCRYPTO_AESNI_C && MBEDCRYPTO_HAVE_X86_64 */
+
+ lo = x[15] & 0xf;
+
+ zh = ctx->HH[lo];
+ zl = ctx->HL[lo];
+
+ for( i = 15; i >= 0; i-- )
+ {
+ lo = x[i] & 0xf;
+ hi = x[i] >> 4;
+
+ if( i != 15 )
+ {
+ rem = (unsigned char) zl & 0xf;
+ zl = ( zh << 60 ) | ( zl >> 4 );
+ zh = ( zh >> 4 );
+ zh ^= (uint64_t) last4[rem] << 48;
+ zh ^= ctx->HH[lo];
+ zl ^= ctx->HL[lo];
+
+ }
+
+ rem = (unsigned char) zl & 0xf;
+ zl = ( zh << 60 ) | ( zl >> 4 );
+ zh = ( zh >> 4 );
+ zh ^= (uint64_t) last4[rem] << 48;
+ zh ^= ctx->HH[hi];
+ zl ^= ctx->HL[hi];
+ }
+
+ PUT_UINT32_BE( zh >> 32, output, 0 );
+ PUT_UINT32_BE( zh, output, 4 );
+ PUT_UINT32_BE( zl >> 32, output, 8 );
+ PUT_UINT32_BE( zl, output, 12 );
+}
+
+int mbedcrypto_gcm_starts( mbedcrypto_gcm_context *ctx,
+ int mode,
+ const unsigned char *iv,
+ size_t iv_len,
+ const unsigned char *add,
+ size_t add_len )
+{
+ int ret;
+ unsigned char work_buf[16];
+ size_t i;
+ const unsigned char *p;
+ size_t use_len, olen = 0;
+
+ /* IV and AD are limited to 2^64 bits, so 2^61 bytes */
+ /* IV is not allowed to be zero length */
+ if( iv_len == 0 ||
+ ( (uint64_t) iv_len ) >> 61 != 0 ||
+ ( (uint64_t) add_len ) >> 61 != 0 )
+ {
+ return( MBEDCRYPTO_ERR_GCM_BAD_INPUT );
+ }
+
+ memset( ctx->y, 0x00, sizeof(ctx->y) );
+ memset( ctx->buf, 0x00, sizeof(ctx->buf) );
+
+ ctx->mode = mode;
+ ctx->len = 0;
+ ctx->add_len = 0;
+
+ if( iv_len == 12 )
+ {
+ memcpy( ctx->y, iv, iv_len );
+ ctx->y[15] = 1;
+ }
+ else
+ {
+ memset( work_buf, 0x00, 16 );
+ PUT_UINT32_BE( iv_len * 8, work_buf, 12 );
+
+ p = iv;
+ while( iv_len > 0 )
+ {
+ use_len = ( iv_len < 16 ) ? iv_len : 16;
+
+ for( i = 0; i < use_len; i++ )
+ ctx->y[i] ^= p[i];
+
+ gcm_mult( ctx, ctx->y, ctx->y );
+
+ iv_len -= use_len;
+ p += use_len;
+ }
+
+ for( i = 0; i < 16; i++ )
+ ctx->y[i] ^= work_buf[i];
+
+ gcm_mult( ctx, ctx->y, ctx->y );
+ }
+
+ if( ( ret = mbedcrypto_cipher_update( &ctx->cipher_ctx, ctx->y, 16, ctx->base_ectr,
+ &olen ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ ctx->add_len = add_len;
+ p = add;
+ while( add_len > 0 )
+ {
+ use_len = ( add_len < 16 ) ? add_len : 16;
+
+ for( i = 0; i < use_len; i++ )
+ ctx->buf[i] ^= p[i];
+
+ gcm_mult( ctx, ctx->buf, ctx->buf );
+
+ add_len -= use_len;
+ p += use_len;
+ }
+
+ return( 0 );
+}
+
+int mbedcrypto_gcm_update( mbedcrypto_gcm_context *ctx,
+ size_t length,
+ const unsigned char *input,
+ unsigned char *output )
+{
+ int ret;
+ unsigned char ectr[16];
+ size_t i;
+ const unsigned char *p;
+ unsigned char *out_p = output;
+ size_t use_len, olen = 0;
+
+ if( output > input && (size_t) ( output - input ) < length )
+ return( MBEDCRYPTO_ERR_GCM_BAD_INPUT );
+
+ /* Total length is restricted to 2^39 - 256 bits, ie 2^36 - 2^5 bytes
+ * Also check for possible overflow */
+ if( ctx->len + length < ctx->len ||
+ (uint64_t) ctx->len + length > 0xFFFFFFFE0ull )
+ {
+ return( MBEDCRYPTO_ERR_GCM_BAD_INPUT );
+ }
+
+ ctx->len += length;
+
+ p = input;
+ while( length > 0 )
+ {
+ use_len = ( length < 16 ) ? length : 16;
+
+ for( i = 16; i > 12; i-- )
+ if( ++ctx->y[i - 1] != 0 )
+ break;
+
+ if( ( ret = mbedcrypto_cipher_update( &ctx->cipher_ctx, ctx->y, 16, ectr,
+ &olen ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ for( i = 0; i < use_len; i++ )
+ {
+ if( ctx->mode == MBEDCRYPTO_GCM_DECRYPT )
+ ctx->buf[i] ^= p[i];
+ out_p[i] = ectr[i] ^ p[i];
+ if( ctx->mode == MBEDCRYPTO_GCM_ENCRYPT )
+ ctx->buf[i] ^= out_p[i];
+ }
+
+ gcm_mult( ctx, ctx->buf, ctx->buf );
+
+ length -= use_len;
+ p += use_len;
+ out_p += use_len;
+ }
+
+ return( 0 );
+}
+
+int mbedcrypto_gcm_finish( mbedcrypto_gcm_context *ctx,
+ unsigned char *tag,
+ size_t tag_len )
+{
+ unsigned char work_buf[16];
+ size_t i;
+ uint64_t orig_len = ctx->len * 8;
+ uint64_t orig_add_len = ctx->add_len * 8;
+
+ if( tag_len > 16 || tag_len < 4 )
+ return( MBEDCRYPTO_ERR_GCM_BAD_INPUT );
+
+ memcpy( tag, ctx->base_ectr, tag_len );
+
+ if( orig_len || orig_add_len )
+ {
+ memset( work_buf, 0x00, 16 );
+
+ PUT_UINT32_BE( ( orig_add_len >> 32 ), work_buf, 0 );
+ PUT_UINT32_BE( ( orig_add_len ), work_buf, 4 );
+ PUT_UINT32_BE( ( orig_len >> 32 ), work_buf, 8 );
+ PUT_UINT32_BE( ( orig_len ), work_buf, 12 );
+
+ for( i = 0; i < 16; i++ )
+ ctx->buf[i] ^= work_buf[i];
+
+ gcm_mult( ctx, ctx->buf, ctx->buf );
+
+ for( i = 0; i < tag_len; i++ )
+ tag[i] ^= ctx->buf[i];
+ }
+
+ return( 0 );
+}
+
+int mbedcrypto_gcm_crypt_and_tag( mbedcrypto_gcm_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,
+ size_t tag_len,
+ unsigned char *tag )
+{
+ int ret;
+
+ if( ( ret = mbedcrypto_gcm_starts( ctx, mode, iv, iv_len, add, add_len ) ) != 0 )
+ return( ret );
+
+ if( ( ret = mbedcrypto_gcm_update( ctx, length, input, output ) ) != 0 )
+ return( ret );
+
+ if( ( ret = mbedcrypto_gcm_finish( ctx, tag, tag_len ) ) != 0 )
+ return( ret );
+
+ return( 0 );
+}
+
+int mbedcrypto_gcm_auth_decrypt( mbedcrypto_gcm_context *ctx,
+ size_t length,
+ const unsigned char *iv,
+ size_t iv_len,
+ const unsigned char *add,
+ size_t add_len,
+ const unsigned char *tag,
+ size_t tag_len,
+ const unsigned char *input,
+ unsigned char *output )
+{
+ int ret;
+ unsigned char check_tag[16];
+ size_t i;
+ int diff;
+
+ if( ( ret = mbedcrypto_gcm_crypt_and_tag( ctx, MBEDCRYPTO_GCM_DECRYPT, length,
+ iv, iv_len, add, add_len,
+ input, output, tag_len, check_tag ) ) != 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 )
+ {
+ mbedcrypto_platform_zeroize( output, length );
+ return( MBEDCRYPTO_ERR_GCM_AUTH_FAILED );
+ }
+
+ return( 0 );
+}
+
+void mbedcrypto_gcm_free( mbedcrypto_gcm_context *ctx )
+{
+ mbedcrypto_cipher_free( &ctx->cipher_ctx );
+ mbedcrypto_platform_zeroize( ctx, sizeof( mbedcrypto_gcm_context ) );
+}
+
+#endif /* !MBEDCRYPTO_GCM_ALT */
+
+#if defined(MBEDCRYPTO_SELF_TEST) && defined(MBEDCRYPTO_AES_C)
+/*
+ * AES-GCM test vectors from:
+ *
+ * http://csrc.nist.gov/groups/STM/cavp/documents/mac/gcmtestvectors.zip
+ */
+#define MAX_TESTS 6
+
+static const int key_index[MAX_TESTS] =
+ { 0, 0, 1, 1, 1, 1 };
+
+static const unsigned char key[MAX_TESTS][32] =
+{
+ { 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 },
+ { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+ 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
+ 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+ 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 },
+};
+
+static const size_t iv_len[MAX_TESTS] =
+ { 12, 12, 12, 12, 8, 60 };
+
+static const int iv_index[MAX_TESTS] =
+ { 0, 0, 1, 1, 1, 2 };
+
+static const unsigned char iv[MAX_TESTS][64] =
+{
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00 },
+ { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
+ 0xde, 0xca, 0xf8, 0x88 },
+ { 0x93, 0x13, 0x22, 0x5d, 0xf8, 0x84, 0x06, 0xe5,
+ 0x55, 0x90, 0x9c, 0x5a, 0xff, 0x52, 0x69, 0xaa,
+ 0x6a, 0x7a, 0x95, 0x38, 0x53, 0x4f, 0x7d, 0xa1,
+ 0xe4, 0xc3, 0x03, 0xd2, 0xa3, 0x18, 0xa7, 0x28,
+ 0xc3, 0xc0, 0xc9, 0x51, 0x56, 0x80, 0x95, 0x39,
+ 0xfc, 0xf0, 0xe2, 0x42, 0x9a, 0x6b, 0x52, 0x54,
+ 0x16, 0xae, 0xdb, 0xf5, 0xa0, 0xde, 0x6a, 0x57,
+ 0xa6, 0x37, 0xb3, 0x9b },
+};
+
+static const size_t add_len[MAX_TESTS] =
+ { 0, 0, 0, 20, 20, 20 };
+
+static const int add_index[MAX_TESTS] =
+ { 0, 0, 0, 1, 1, 1 };
+
+static const unsigned char additional[MAX_TESTS][64] =
+{
+ { 0x00 },
+ { 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+ 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+ 0xab, 0xad, 0xda, 0xd2 },
+};
+
+static const size_t pt_len[MAX_TESTS] =
+ { 0, 16, 64, 60, 60, 60 };
+
+static const int pt_index[MAX_TESTS] =
+ { 0, 0, 1, 1, 1, 1 };
+
+static const unsigned char pt[MAX_TESTS][64] =
+{
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
+ 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
+ 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
+ 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
+ 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
+ 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
+ 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
+ 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55 },
+};
+
+static const unsigned char ct[MAX_TESTS * 3][64] =
+{
+ { 0x00 },
+ { 0x03, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92,
+ 0xf3, 0x28, 0xc2, 0xb9, 0x71, 0xb2, 0xfe, 0x78 },
+ { 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24,
+ 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c,
+ 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0,
+ 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e,
+ 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c,
+ 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05,
+ 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97,
+ 0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85 },
+ { 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24,
+ 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c,
+ 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0,
+ 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e,
+ 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c,
+ 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05,
+ 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97,
+ 0x3d, 0x58, 0xe0, 0x91 },
+ { 0x61, 0x35, 0x3b, 0x4c, 0x28, 0x06, 0x93, 0x4a,
+ 0x77, 0x7f, 0xf5, 0x1f, 0xa2, 0x2a, 0x47, 0x55,
+ 0x69, 0x9b, 0x2a, 0x71, 0x4f, 0xcd, 0xc6, 0xf8,
+ 0x37, 0x66, 0xe5, 0xf9, 0x7b, 0x6c, 0x74, 0x23,
+ 0x73, 0x80, 0x69, 0x00, 0xe4, 0x9f, 0x24, 0xb2,
+ 0x2b, 0x09, 0x75, 0x44, 0xd4, 0x89, 0x6b, 0x42,
+ 0x49, 0x89, 0xb5, 0xe1, 0xeb, 0xac, 0x0f, 0x07,
+ 0xc2, 0x3f, 0x45, 0x98 },
+ { 0x8c, 0xe2, 0x49, 0x98, 0x62, 0x56, 0x15, 0xb6,
+ 0x03, 0xa0, 0x33, 0xac, 0xa1, 0x3f, 0xb8, 0x94,
+ 0xbe, 0x91, 0x12, 0xa5, 0xc3, 0xa2, 0x11, 0xa8,
+ 0xba, 0x26, 0x2a, 0x3c, 0xca, 0x7e, 0x2c, 0xa7,
+ 0x01, 0xe4, 0xa9, 0xa4, 0xfb, 0xa4, 0x3c, 0x90,
+ 0xcc, 0xdc, 0xb2, 0x81, 0xd4, 0x8c, 0x7c, 0x6f,
+ 0xd6, 0x28, 0x75, 0xd2, 0xac, 0xa4, 0x17, 0x03,
+ 0x4c, 0x34, 0xae, 0xe5 },
+ { 0x00 },
+ { 0x98, 0xe7, 0x24, 0x7c, 0x07, 0xf0, 0xfe, 0x41,
+ 0x1c, 0x26, 0x7e, 0x43, 0x84, 0xb0, 0xf6, 0x00 },
+ { 0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41,
+ 0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a, 0x27, 0x57,
+ 0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84,
+ 0x62, 0x85, 0x93, 0xb4, 0x0c, 0xa1, 0xe1, 0x9c,
+ 0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25,
+ 0xac, 0x61, 0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47,
+ 0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9,
+ 0xcc, 0xda, 0x27, 0x10, 0xac, 0xad, 0xe2, 0x56 },
+ { 0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41,
+ 0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a, 0x27, 0x57,
+ 0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84,
+ 0x62, 0x85, 0x93, 0xb4, 0x0c, 0xa1, 0xe1, 0x9c,
+ 0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25,
+ 0xac, 0x61, 0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47,
+ 0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9,
+ 0xcc, 0xda, 0x27, 0x10 },
+ { 0x0f, 0x10, 0xf5, 0x99, 0xae, 0x14, 0xa1, 0x54,
+ 0xed, 0x24, 0xb3, 0x6e, 0x25, 0x32, 0x4d, 0xb8,
+ 0xc5, 0x66, 0x63, 0x2e, 0xf2, 0xbb, 0xb3, 0x4f,
+ 0x83, 0x47, 0x28, 0x0f, 0xc4, 0x50, 0x70, 0x57,
+ 0xfd, 0xdc, 0x29, 0xdf, 0x9a, 0x47, 0x1f, 0x75,
+ 0xc6, 0x65, 0x41, 0xd4, 0xd4, 0xda, 0xd1, 0xc9,
+ 0xe9, 0x3a, 0x19, 0xa5, 0x8e, 0x8b, 0x47, 0x3f,
+ 0xa0, 0xf0, 0x62, 0xf7 },
+ { 0xd2, 0x7e, 0x88, 0x68, 0x1c, 0xe3, 0x24, 0x3c,
+ 0x48, 0x30, 0x16, 0x5a, 0x8f, 0xdc, 0xf9, 0xff,
+ 0x1d, 0xe9, 0xa1, 0xd8, 0xe6, 0xb4, 0x47, 0xef,
+ 0x6e, 0xf7, 0xb7, 0x98, 0x28, 0x66, 0x6e, 0x45,
+ 0x81, 0xe7, 0x90, 0x12, 0xaf, 0x34, 0xdd, 0xd9,
+ 0xe2, 0xf0, 0x37, 0x58, 0x9b, 0x29, 0x2d, 0xb3,
+ 0xe6, 0x7c, 0x03, 0x67, 0x45, 0xfa, 0x22, 0xe7,
+ 0xe9, 0xb7, 0x37, 0x3b },
+ { 0x00 },
+ { 0xce, 0xa7, 0x40, 0x3d, 0x4d, 0x60, 0x6b, 0x6e,
+ 0x07, 0x4e, 0xc5, 0xd3, 0xba, 0xf3, 0x9d, 0x18 },
+ { 0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07,
+ 0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d,
+ 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9,
+ 0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa,
+ 0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d,
+ 0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38,
+ 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a,
+ 0xbc, 0xc9, 0xf6, 0x62, 0x89, 0x80, 0x15, 0xad },
+ { 0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07,
+ 0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d,
+ 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9,
+ 0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa,
+ 0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d,
+ 0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38,
+ 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a,
+ 0xbc, 0xc9, 0xf6, 0x62 },
+ { 0xc3, 0x76, 0x2d, 0xf1, 0xca, 0x78, 0x7d, 0x32,
+ 0xae, 0x47, 0xc1, 0x3b, 0xf1, 0x98, 0x44, 0xcb,
+ 0xaf, 0x1a, 0xe1, 0x4d, 0x0b, 0x97, 0x6a, 0xfa,
+ 0xc5, 0x2f, 0xf7, 0xd7, 0x9b, 0xba, 0x9d, 0xe0,
+ 0xfe, 0xb5, 0x82, 0xd3, 0x39, 0x34, 0xa4, 0xf0,
+ 0x95, 0x4c, 0xc2, 0x36, 0x3b, 0xc7, 0x3f, 0x78,
+ 0x62, 0xac, 0x43, 0x0e, 0x64, 0xab, 0xe4, 0x99,
+ 0xf4, 0x7c, 0x9b, 0x1f },
+ { 0x5a, 0x8d, 0xef, 0x2f, 0x0c, 0x9e, 0x53, 0xf1,
+ 0xf7, 0x5d, 0x78, 0x53, 0x65, 0x9e, 0x2a, 0x20,
+ 0xee, 0xb2, 0xb2, 0x2a, 0xaf, 0xde, 0x64, 0x19,
+ 0xa0, 0x58, 0xab, 0x4f, 0x6f, 0x74, 0x6b, 0xf4,
+ 0x0f, 0xc0, 0xc3, 0xb7, 0x80, 0xf2, 0x44, 0x45,
+ 0x2d, 0xa3, 0xeb, 0xf1, 0xc5, 0xd8, 0x2c, 0xde,
+ 0xa2, 0x41, 0x89, 0x97, 0x20, 0x0e, 0xf8, 0x2e,
+ 0x44, 0xae, 0x7e, 0x3f },
+};
+
+static const unsigned char tag[MAX_TESTS * 3][16] =
+{
+ { 0x58, 0xe2, 0xfc, 0xce, 0xfa, 0x7e, 0x30, 0x61,
+ 0x36, 0x7f, 0x1d, 0x57, 0xa4, 0xe7, 0x45, 0x5a },
+ { 0xab, 0x6e, 0x47, 0xd4, 0x2c, 0xec, 0x13, 0xbd,
+ 0xf5, 0x3a, 0x67, 0xb2, 0x12, 0x57, 0xbd, 0xdf },
+ { 0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6,
+ 0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6, 0xfa, 0xb4 },
+ { 0x5b, 0xc9, 0x4f, 0xbc, 0x32, 0x21, 0xa5, 0xdb,
+ 0x94, 0xfa, 0xe9, 0x5a, 0xe7, 0x12, 0x1a, 0x47 },
+ { 0x36, 0x12, 0xd2, 0xe7, 0x9e, 0x3b, 0x07, 0x85,
+ 0x56, 0x1b, 0xe1, 0x4a, 0xac, 0xa2, 0xfc, 0xcb },
+ { 0x61, 0x9c, 0xc5, 0xae, 0xff, 0xfe, 0x0b, 0xfa,
+ 0x46, 0x2a, 0xf4, 0x3c, 0x16, 0x99, 0xd0, 0x50 },
+ { 0xcd, 0x33, 0xb2, 0x8a, 0xc7, 0x73, 0xf7, 0x4b,
+ 0xa0, 0x0e, 0xd1, 0xf3, 0x12, 0x57, 0x24, 0x35 },
+ { 0x2f, 0xf5, 0x8d, 0x80, 0x03, 0x39, 0x27, 0xab,
+ 0x8e, 0xf4, 0xd4, 0x58, 0x75, 0x14, 0xf0, 0xfb },
+ { 0x99, 0x24, 0xa7, 0xc8, 0x58, 0x73, 0x36, 0xbf,
+ 0xb1, 0x18, 0x02, 0x4d, 0xb8, 0x67, 0x4a, 0x14 },
+ { 0x25, 0x19, 0x49, 0x8e, 0x80, 0xf1, 0x47, 0x8f,
+ 0x37, 0xba, 0x55, 0xbd, 0x6d, 0x27, 0x61, 0x8c },
+ { 0x65, 0xdc, 0xc5, 0x7f, 0xcf, 0x62, 0x3a, 0x24,
+ 0x09, 0x4f, 0xcc, 0xa4, 0x0d, 0x35, 0x33, 0xf8 },
+ { 0xdc, 0xf5, 0x66, 0xff, 0x29, 0x1c, 0x25, 0xbb,
+ 0xb8, 0x56, 0x8f, 0xc3, 0xd3, 0x76, 0xa6, 0xd9 },
+ { 0x53, 0x0f, 0x8a, 0xfb, 0xc7, 0x45, 0x36, 0xb9,
+ 0xa9, 0x63, 0xb4, 0xf1, 0xc4, 0xcb, 0x73, 0x8b },
+ { 0xd0, 0xd1, 0xc8, 0xa7, 0x99, 0x99, 0x6b, 0xf0,
+ 0x26, 0x5b, 0x98, 0xb5, 0xd4, 0x8a, 0xb9, 0x19 },
+ { 0xb0, 0x94, 0xda, 0xc5, 0xd9, 0x34, 0x71, 0xbd,
+ 0xec, 0x1a, 0x50, 0x22, 0x70, 0xe3, 0xcc, 0x6c },
+ { 0x76, 0xfc, 0x6e, 0xce, 0x0f, 0x4e, 0x17, 0x68,
+ 0xcd, 0xdf, 0x88, 0x53, 0xbb, 0x2d, 0x55, 0x1b },
+ { 0x3a, 0x33, 0x7d, 0xbf, 0x46, 0xa7, 0x92, 0xc4,
+ 0x5e, 0x45, 0x49, 0x13, 0xfe, 0x2e, 0xa8, 0xf2 },
+ { 0xa4, 0x4a, 0x82, 0x66, 0xee, 0x1c, 0x8e, 0xb0,
+ 0xc8, 0xb5, 0xd4, 0xcf, 0x5a, 0xe9, 0xf1, 0x9a },
+};
+
+int mbedcrypto_gcm_self_test( int verbose )
+{
+ mbedcrypto_gcm_context ctx;
+ unsigned char buf[64];
+ unsigned char tag_buf[16];
+ int i, j, ret;
+ mbedcrypto_cipher_id_t cipher = MBEDCRYPTO_CIPHER_ID_AES;
+
+ for( j = 0; j < 3; j++ )
+ {
+ int key_len = 128 + 64 * j;
+
+ for( i = 0; i < MAX_TESTS; i++ )
+ {
+ mbedcrypto_gcm_init( &ctx );
+
+ if( verbose != 0 )
+ mbedcrypto_printf( " AES-GCM-%3d #%d (%s): ",
+ key_len, i, "enc" );
+
+ ret = mbedcrypto_gcm_setkey( &ctx, cipher, key[key_index[i]],
+ key_len );
+ /*
+ * AES-192 is an optional feature that may be unavailable when
+ * there is an alternative underlying implementation i.e. when
+ * MBEDCRYPTO_AES_ALT is defined.
+ */
+ if( ret == MBEDCRYPTO_ERR_AES_FEATURE_UNAVAILABLE && key_len == 192 )
+ {
+ mbedcrypto_printf( "skipped\n" );
+ break;
+ }
+ else if( ret != 0 )
+ {
+ goto exit;
+ }
+
+ ret = mbedcrypto_gcm_crypt_and_tag( &ctx, MBEDCRYPTO_GCM_ENCRYPT,
+ pt_len[i],
+ iv[iv_index[i]], iv_len[i],
+ additional[add_index[i]], add_len[i],
+ pt[pt_index[i]], buf, 16, tag_buf );
+ if( ret != 0 )
+ goto exit;
+
+ if ( memcmp( buf, ct[j * 6 + i], pt_len[i] ) != 0 ||
+ memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 )
+ {
+ ret = 1;
+ goto exit;
+ }
+
+ mbedcrypto_gcm_free( &ctx );
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+
+ mbedcrypto_gcm_init( &ctx );
+
+ if( verbose != 0 )
+ mbedcrypto_printf( " AES-GCM-%3d #%d (%s): ",
+ key_len, i, "dec" );
+
+ ret = mbedcrypto_gcm_setkey( &ctx, cipher, key[key_index[i]],
+ key_len );
+ if( ret != 0 )
+ goto exit;
+
+ ret = mbedcrypto_gcm_crypt_and_tag( &ctx, MBEDCRYPTO_GCM_DECRYPT,
+ pt_len[i],
+ iv[iv_index[i]], iv_len[i],
+ additional[add_index[i]], add_len[i],
+ ct[j * 6 + i], buf, 16, tag_buf );
+
+ if( ret != 0 )
+ goto exit;
+
+ if( memcmp( buf, pt[pt_index[i]], pt_len[i] ) != 0 ||
+ memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 )
+ {
+ ret = 1;
+ goto exit;
+ }
+
+ mbedcrypto_gcm_free( &ctx );
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+
+ mbedcrypto_gcm_init( &ctx );
+
+ if( verbose != 0 )
+ mbedcrypto_printf( " AES-GCM-%3d #%d split (%s): ",
+ key_len, i, "enc" );
+
+ ret = mbedcrypto_gcm_setkey( &ctx, cipher, key[key_index[i]],
+ key_len );
+ if( ret != 0 )
+ goto exit;
+
+ ret = mbedcrypto_gcm_starts( &ctx, MBEDCRYPTO_GCM_ENCRYPT,
+ iv[iv_index[i]], iv_len[i],
+ additional[add_index[i]], add_len[i] );
+ if( ret != 0 )
+ goto exit;
+
+ if( pt_len[i] > 32 )
+ {
+ size_t rest_len = pt_len[i] - 32;
+ ret = mbedcrypto_gcm_update( &ctx, 32, pt[pt_index[i]], buf );
+ if( ret != 0 )
+ goto exit;
+
+ ret = mbedcrypto_gcm_update( &ctx, rest_len, pt[pt_index[i]] + 32,
+ buf + 32 );
+ if( ret != 0 )
+ goto exit;
+ }
+ else
+ {
+ ret = mbedcrypto_gcm_update( &ctx, pt_len[i], pt[pt_index[i]], buf );
+ if( ret != 0 )
+ goto exit;
+ }
+
+ ret = mbedcrypto_gcm_finish( &ctx, tag_buf, 16 );
+ if( ret != 0 )
+ goto exit;
+
+ if( memcmp( buf, ct[j * 6 + i], pt_len[i] ) != 0 ||
+ memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 )
+ {
+ ret = 1;
+ goto exit;
+ }
+
+ mbedcrypto_gcm_free( &ctx );
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+
+ mbedcrypto_gcm_init( &ctx );
+
+ if( verbose != 0 )
+ mbedcrypto_printf( " AES-GCM-%3d #%d split (%s): ",
+ key_len, i, "dec" );
+
+ ret = mbedcrypto_gcm_setkey( &ctx, cipher, key[key_index[i]],
+ key_len );
+ if( ret != 0 )
+ goto exit;
+
+ ret = mbedcrypto_gcm_starts( &ctx, MBEDCRYPTO_GCM_DECRYPT,
+ iv[iv_index[i]], iv_len[i],
+ additional[add_index[i]], add_len[i] );
+ if( ret != 0 )
+ goto exit;
+
+ if( pt_len[i] > 32 )
+ {
+ size_t rest_len = pt_len[i] - 32;
+ ret = mbedcrypto_gcm_update( &ctx, 32, ct[j * 6 + i], buf );
+ if( ret != 0 )
+ goto exit;
+
+ ret = mbedcrypto_gcm_update( &ctx, rest_len, ct[j * 6 + i] + 32,
+ buf + 32 );
+ if( ret != 0 )
+ goto exit;
+ }
+ else
+ {
+ ret = mbedcrypto_gcm_update( &ctx, pt_len[i], ct[j * 6 + i],
+ buf );
+ if( ret != 0 )
+ goto exit;
+ }
+
+ ret = mbedcrypto_gcm_finish( &ctx, tag_buf, 16 );
+ if( ret != 0 )
+ goto exit;
+
+ if( memcmp( buf, pt[pt_index[i]], pt_len[i] ) != 0 ||
+ memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 )
+ {
+ ret = 1;
+ goto exit;
+ }
+
+ mbedcrypto_gcm_free( &ctx );
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+ }
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "\n" );
+
+ ret = 0;
+
+exit:
+ if( ret != 0 )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+ mbedcrypto_gcm_free( &ctx );
+ }
+
+ return( ret );
+}
+
+#endif /* MBEDCRYPTO_SELF_TEST && MBEDCRYPTO_AES_C */
+
+#endif /* MBEDCRYPTO_GCM_C */
diff --git a/library/hmac_drbg.c b/library/hmac_drbg.c
new file mode 100644
index 0000000..aff2cdb
--- /dev/null
+++ b/library/hmac_drbg.c
@@ -0,0 +1,530 @@
+/*
+ * HMAC_DRBG implementation (NIST SP 800-90)
+ *
+ * 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 Crypto (https://tls.mbed.org)
+ */
+
+/*
+ * The NIST SP 800-90A DRBGs are described in the following publication.
+ * http://csrc.nist.gov/publications/nistpubs/800-90A/SP800-90A.pdf
+ * References below are based on rev. 1 (January 2012).
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_HMAC_DRBG_C)
+
+#include "mbedcrypto/hmac_drbg.h"
+#include "mbedcrypto/platform_util.h"
+
+#include <string.h>
+
+#if defined(MBEDCRYPTO_FS_IO)
+#include <stdio.h>
+#endif
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#include <stdio.h>
+#define mbedcrypto_printf printf
+#endif /* MBEDCRYPTO_SELF_TEST */
+#endif /* MBEDCRYPTO_PLATFORM_C */
+
+/*
+ * HMAC_DRBG context initialization
+ */
+void mbedcrypto_hmac_drbg_init( mbedcrypto_hmac_drbg_context *ctx )
+{
+ memset( ctx, 0, sizeof( mbedcrypto_hmac_drbg_context ) );
+
+#if defined(MBEDCRYPTO_THREADING_C)
+ mbedcrypto_mutex_init( &ctx->mutex );
+#endif
+}
+
+/*
+ * HMAC_DRBG update, using optional additional data (10.1.2.2)
+ */
+void mbedcrypto_hmac_drbg_update( mbedcrypto_hmac_drbg_context *ctx,
+ const unsigned char *additional, size_t add_len )
+{
+ size_t md_len = mbedcrypto_md_get_size( ctx->md_ctx.md_info );
+ unsigned char rounds = ( additional != NULL && add_len != 0 ) ? 2 : 1;
+ unsigned char sep[1];
+ unsigned char K[MBEDCRYPTO_MD_MAX_SIZE];
+
+ for( sep[0] = 0; sep[0] < rounds; sep[0]++ )
+ {
+ /* Step 1 or 4 */
+ mbedcrypto_md_hmac_reset( &ctx->md_ctx );
+ mbedcrypto_md_hmac_update( &ctx->md_ctx, ctx->V, md_len );
+ mbedcrypto_md_hmac_update( &ctx->md_ctx, sep, 1 );
+ if( rounds == 2 )
+ mbedcrypto_md_hmac_update( &ctx->md_ctx, additional, add_len );
+ mbedcrypto_md_hmac_finish( &ctx->md_ctx, K );
+
+ /* Step 2 or 5 */
+ mbedcrypto_md_hmac_starts( &ctx->md_ctx, K, md_len );
+ mbedcrypto_md_hmac_update( &ctx->md_ctx, ctx->V, md_len );
+ mbedcrypto_md_hmac_finish( &ctx->md_ctx, ctx->V );
+ }
+}
+
+/*
+ * Simplified HMAC_DRBG initialisation (for use with deterministic ECDSA)
+ */
+int mbedcrypto_hmac_drbg_seed_buf( mbedcrypto_hmac_drbg_context *ctx,
+ const mbedcrypto_md_info_t * md_info,
+ const unsigned char *data, size_t data_len )
+{
+ int ret;
+
+ if( ( ret = mbedcrypto_md_setup( &ctx->md_ctx, md_info, 1 ) ) != 0 )
+ return( ret );
+
+ /*
+ * Set initial working state.
+ * Use the V memory location, which is currently all 0, to initialize the
+ * MD context with an all-zero key. Then set V to its initial value.
+ */
+ mbedcrypto_md_hmac_starts( &ctx->md_ctx, ctx->V, mbedcrypto_md_get_size( md_info ) );
+ memset( ctx->V, 0x01, mbedcrypto_md_get_size( md_info ) );
+
+ mbedcrypto_hmac_drbg_update( ctx, data, data_len );
+
+ return( 0 );
+}
+
+/*
+ * HMAC_DRBG reseeding: 10.1.2.4 (arabic) + 9.2 (Roman)
+ */
+int mbedcrypto_hmac_drbg_reseed( mbedcrypto_hmac_drbg_context *ctx,
+ const unsigned char *additional, size_t len )
+{
+ unsigned char seed[MBEDCRYPTO_HMAC_DRBG_MAX_SEED_INPUT];
+ size_t seedlen;
+
+ /* III. Check input length */
+ if( len > MBEDCRYPTO_HMAC_DRBG_MAX_INPUT ||
+ ctx->entropy_len + len > MBEDCRYPTO_HMAC_DRBG_MAX_SEED_INPUT )
+ {
+ return( MBEDCRYPTO_ERR_HMAC_DRBG_INPUT_TOO_BIG );
+ }
+
+ memset( seed, 0, MBEDCRYPTO_HMAC_DRBG_MAX_SEED_INPUT );
+
+ /* IV. Gather entropy_len bytes of entropy for the seed */
+ if( ctx->f_entropy( ctx->p_entropy, seed, ctx->entropy_len ) != 0 )
+ return( MBEDCRYPTO_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED );
+
+ seedlen = ctx->entropy_len;
+
+ /* 1. Concatenate entropy and additional data if any */
+ if( additional != NULL && len != 0 )
+ {
+ memcpy( seed + seedlen, additional, len );
+ seedlen += len;
+ }
+
+ /* 2. Update state */
+ mbedcrypto_hmac_drbg_update( ctx, seed, seedlen );
+
+ /* 3. Reset reseed_counter */
+ ctx->reseed_counter = 1;
+
+ /* 4. Done */
+ return( 0 );
+}
+
+/*
+ * HMAC_DRBG initialisation (10.1.2.3 + 9.1)
+ */
+int mbedcrypto_hmac_drbg_seed( mbedcrypto_hmac_drbg_context *ctx,
+ const mbedcrypto_md_info_t * md_info,
+ int (*f_entropy)(void *, unsigned char *, size_t),
+ void *p_entropy,
+ const unsigned char *custom,
+ size_t len )
+{
+ int ret;
+ size_t entropy_len, md_size;
+
+ if( ( ret = mbedcrypto_md_setup( &ctx->md_ctx, md_info, 1 ) ) != 0 )
+ return( ret );
+
+ md_size = mbedcrypto_md_get_size( md_info );
+
+ /*
+ * Set initial working state.
+ * Use the V memory location, which is currently all 0, to initialize the
+ * MD context with an all-zero key. Then set V to its initial value.
+ */
+ mbedcrypto_md_hmac_starts( &ctx->md_ctx, ctx->V, md_size );
+ memset( ctx->V, 0x01, md_size );
+
+ ctx->f_entropy = f_entropy;
+ ctx->p_entropy = p_entropy;
+
+ ctx->reseed_interval = MBEDCRYPTO_HMAC_DRBG_RESEED_INTERVAL;
+
+ /*
+ * See SP800-57 5.6.1 (p. 65-66) for the security strength provided by
+ * each hash function, then according to SP800-90A rev1 10.1 table 2,
+ * min_entropy_len (in bits) is security_strength.
+ *
+ * (This also matches the sizes used in the NIST test vectors.)
+ */
+ entropy_len = md_size <= 20 ? 16 : /* 160-bits hash -> 128 bits */
+ md_size <= 28 ? 24 : /* 224-bits hash -> 192 bits */
+ 32; /* better (256+) -> 256 bits */
+
+ /*
+ * For initialisation, use more entropy to emulate a nonce
+ * (Again, matches test vectors.)
+ */
+ ctx->entropy_len = entropy_len * 3 / 2;
+
+ if( ( ret = mbedcrypto_hmac_drbg_reseed( ctx, custom, len ) ) != 0 )
+ return( ret );
+
+ ctx->entropy_len = entropy_len;
+
+ return( 0 );
+}
+
+/*
+ * Set prediction resistance
+ */
+void mbedcrypto_hmac_drbg_set_prediction_resistance( mbedcrypto_hmac_drbg_context *ctx,
+ int resistance )
+{
+ ctx->prediction_resistance = resistance;
+}
+
+/*
+ * Set entropy length grabbed for reseeds
+ */
+void mbedcrypto_hmac_drbg_set_entropy_len( mbedcrypto_hmac_drbg_context *ctx, size_t len )
+{
+ ctx->entropy_len = len;
+}
+
+/*
+ * Set reseed interval
+ */
+void mbedcrypto_hmac_drbg_set_reseed_interval( mbedcrypto_hmac_drbg_context *ctx, int interval )
+{
+ ctx->reseed_interval = interval;
+}
+
+/*
+ * HMAC_DRBG random function with optional additional data:
+ * 10.1.2.5 (arabic) + 9.3 (Roman)
+ */
+int mbedcrypto_hmac_drbg_random_with_add( void *p_rng,
+ unsigned char *output, size_t out_len,
+ const unsigned char *additional, size_t add_len )
+{
+ int ret;
+ mbedcrypto_hmac_drbg_context *ctx = (mbedcrypto_hmac_drbg_context *) p_rng;
+ size_t md_len = mbedcrypto_md_get_size( ctx->md_ctx.md_info );
+ size_t left = out_len;
+ unsigned char *out = output;
+
+ /* II. Check request length */
+ if( out_len > MBEDCRYPTO_HMAC_DRBG_MAX_REQUEST )
+ return( MBEDCRYPTO_ERR_HMAC_DRBG_REQUEST_TOO_BIG );
+
+ /* III. Check input length */
+ if( add_len > MBEDCRYPTO_HMAC_DRBG_MAX_INPUT )
+ return( MBEDCRYPTO_ERR_HMAC_DRBG_INPUT_TOO_BIG );
+
+ /* 1. (aka VII and IX) Check reseed counter and PR */
+ if( ctx->f_entropy != NULL && /* For no-reseeding instances */
+ ( ctx->prediction_resistance == MBEDCRYPTO_HMAC_DRBG_PR_ON ||
+ ctx->reseed_counter > ctx->reseed_interval ) )
+ {
+ if( ( ret = mbedcrypto_hmac_drbg_reseed( ctx, additional, add_len ) ) != 0 )
+ return( ret );
+
+ add_len = 0; /* VII.4 */
+ }
+
+ /* 2. Use additional data if any */
+ if( additional != NULL && add_len != 0 )
+ mbedcrypto_hmac_drbg_update( ctx, additional, add_len );
+
+ /* 3, 4, 5. Generate bytes */
+ while( left != 0 )
+ {
+ size_t use_len = left > md_len ? md_len : left;
+
+ mbedcrypto_md_hmac_reset( &ctx->md_ctx );
+ mbedcrypto_md_hmac_update( &ctx->md_ctx, ctx->V, md_len );
+ mbedcrypto_md_hmac_finish( &ctx->md_ctx, ctx->V );
+
+ memcpy( out, ctx->V, use_len );
+ out += use_len;
+ left -= use_len;
+ }
+
+ /* 6. Update */
+ mbedcrypto_hmac_drbg_update( ctx, additional, add_len );
+
+ /* 7. Update reseed counter */
+ ctx->reseed_counter++;
+
+ /* 8. Done */
+ return( 0 );
+}
+
+/*
+ * HMAC_DRBG random function
+ */
+int mbedcrypto_hmac_drbg_random( void *p_rng, unsigned char *output, size_t out_len )
+{
+ int ret;
+ mbedcrypto_hmac_drbg_context *ctx = (mbedcrypto_hmac_drbg_context *) p_rng;
+
+#if defined(MBEDCRYPTO_THREADING_C)
+ if( ( ret = mbedcrypto_mutex_lock( &ctx->mutex ) ) != 0 )
+ return( ret );
+#endif
+
+ ret = mbedcrypto_hmac_drbg_random_with_add( ctx, output, out_len, NULL, 0 );
+
+#if defined(MBEDCRYPTO_THREADING_C)
+ if( mbedcrypto_mutex_unlock( &ctx->mutex ) != 0 )
+ return( MBEDCRYPTO_ERR_THREADING_MUTEX_ERROR );
+#endif
+
+ return( ret );
+}
+
+/*
+ * Free an HMAC_DRBG context
+ */
+void mbedcrypto_hmac_drbg_free( mbedcrypto_hmac_drbg_context *ctx )
+{
+ if( ctx == NULL )
+ return;
+
+#if defined(MBEDCRYPTO_THREADING_C)
+ mbedcrypto_mutex_free( &ctx->mutex );
+#endif
+ mbedcrypto_md_free( &ctx->md_ctx );
+ mbedcrypto_platform_zeroize( ctx, sizeof( mbedcrypto_hmac_drbg_context ) );
+}
+
+#if defined(MBEDCRYPTO_FS_IO)
+int mbedcrypto_hmac_drbg_write_seed_file( mbedcrypto_hmac_drbg_context *ctx, const char *path )
+{
+ int ret;
+ FILE *f;
+ unsigned char buf[ MBEDCRYPTO_HMAC_DRBG_MAX_INPUT ];
+
+ if( ( f = fopen( path, "wb" ) ) == NULL )
+ return( MBEDCRYPTO_ERR_HMAC_DRBG_FILE_IO_ERROR );
+
+ if( ( ret = mbedcrypto_hmac_drbg_random( ctx, buf, sizeof( buf ) ) ) != 0 )
+ goto exit;
+
+ if( fwrite( buf, 1, sizeof( buf ), f ) != sizeof( buf ) )
+ {
+ ret = MBEDCRYPTO_ERR_HMAC_DRBG_FILE_IO_ERROR;
+ goto exit;
+ }
+
+ ret = 0;
+
+exit:
+ fclose( f );
+ mbedcrypto_platform_zeroize( buf, sizeof( buf ) );
+
+ return( ret );
+}
+
+int mbedcrypto_hmac_drbg_update_seed_file( mbedcrypto_hmac_drbg_context *ctx, const char *path )
+{
+ int ret = 0;
+ FILE *f;
+ size_t n;
+ unsigned char buf[ MBEDCRYPTO_HMAC_DRBG_MAX_INPUT ];
+
+ if( ( f = fopen( path, "rb" ) ) == NULL )
+ return( MBEDCRYPTO_ERR_HMAC_DRBG_FILE_IO_ERROR );
+
+ fseek( f, 0, SEEK_END );
+ n = (size_t) ftell( f );
+ fseek( f, 0, SEEK_SET );
+
+ if( n > MBEDCRYPTO_HMAC_DRBG_MAX_INPUT )
+ {
+ fclose( f );
+ return( MBEDCRYPTO_ERR_HMAC_DRBG_INPUT_TOO_BIG );
+ }
+
+ if( fread( buf, 1, n, f ) != n )
+ ret = MBEDCRYPTO_ERR_HMAC_DRBG_FILE_IO_ERROR;
+ else
+ mbedcrypto_hmac_drbg_update( ctx, buf, n );
+
+ fclose( f );
+
+ mbedcrypto_platform_zeroize( buf, sizeof( buf ) );
+
+ if( ret != 0 )
+ return( ret );
+
+ return( mbedcrypto_hmac_drbg_write_seed_file( ctx, path ) );
+}
+#endif /* MBEDCRYPTO_FS_IO */
+
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+
+#if !defined(MBEDCRYPTO_SHA1_C)
+/* Dummy checkup routine */
+int mbedcrypto_hmac_drbg_self_test( int verbose )
+{
+ (void) verbose;
+ return( 0 );
+}
+#else
+
+#define OUTPUT_LEN 80
+
+/* From a NIST PR=true test vector */
+static const unsigned char entropy_pr[] = {
+ 0xa0, 0xc9, 0xab, 0x58, 0xf1, 0xe2, 0xe5, 0xa4, 0xde, 0x3e, 0xbd, 0x4f,
+ 0xf7, 0x3e, 0x9c, 0x5b, 0x64, 0xef, 0xd8, 0xca, 0x02, 0x8c, 0xf8, 0x11,
+ 0x48, 0xa5, 0x84, 0xfe, 0x69, 0xab, 0x5a, 0xee, 0x42, 0xaa, 0x4d, 0x42,
+ 0x17, 0x60, 0x99, 0xd4, 0x5e, 0x13, 0x97, 0xdc, 0x40, 0x4d, 0x86, 0xa3,
+ 0x7b, 0xf5, 0x59, 0x54, 0x75, 0x69, 0x51, 0xe4 };
+static const unsigned char result_pr[OUTPUT_LEN] = {
+ 0x9a, 0x00, 0xa2, 0xd0, 0x0e, 0xd5, 0x9b, 0xfe, 0x31, 0xec, 0xb1, 0x39,
+ 0x9b, 0x60, 0x81, 0x48, 0xd1, 0x96, 0x9d, 0x25, 0x0d, 0x3c, 0x1e, 0x94,
+ 0x10, 0x10, 0x98, 0x12, 0x93, 0x25, 0xca, 0xb8, 0xfc, 0xcc, 0x2d, 0x54,
+ 0x73, 0x19, 0x70, 0xc0, 0x10, 0x7a, 0xa4, 0x89, 0x25, 0x19, 0x95, 0x5e,
+ 0x4b, 0xc6, 0x00, 0x1d, 0x7f, 0x4e, 0x6a, 0x2b, 0xf8, 0xa3, 0x01, 0xab,
+ 0x46, 0x05, 0x5c, 0x09, 0xa6, 0x71, 0x88, 0xf1, 0xa7, 0x40, 0xee, 0xf3,
+ 0xe1, 0x5c, 0x02, 0x9b, 0x44, 0xaf, 0x03, 0x44 };
+
+/* From a NIST PR=false test vector */
+static const unsigned char entropy_nopr[] = {
+ 0x79, 0x34, 0x9b, 0xbf, 0x7c, 0xdd, 0xa5, 0x79, 0x95, 0x57, 0x86, 0x66,
+ 0x21, 0xc9, 0x13, 0x83, 0x11, 0x46, 0x73, 0x3a, 0xbf, 0x8c, 0x35, 0xc8,
+ 0xc7, 0x21, 0x5b, 0x5b, 0x96, 0xc4, 0x8e, 0x9b, 0x33, 0x8c, 0x74, 0xe3,
+ 0xe9, 0x9d, 0xfe, 0xdf };
+static const unsigned char result_nopr[OUTPUT_LEN] = {
+ 0xc6, 0xa1, 0x6a, 0xb8, 0xd4, 0x20, 0x70, 0x6f, 0x0f, 0x34, 0xab, 0x7f,
+ 0xec, 0x5a, 0xdc, 0xa9, 0xd8, 0xca, 0x3a, 0x13, 0x3e, 0x15, 0x9c, 0xa6,
+ 0xac, 0x43, 0xc6, 0xf8, 0xa2, 0xbe, 0x22, 0x83, 0x4a, 0x4c, 0x0a, 0x0a,
+ 0xff, 0xb1, 0x0d, 0x71, 0x94, 0xf1, 0xc1, 0xa5, 0xcf, 0x73, 0x22, 0xec,
+ 0x1a, 0xe0, 0x96, 0x4e, 0xd4, 0xbf, 0x12, 0x27, 0x46, 0xe0, 0x87, 0xfd,
+ 0xb5, 0xb3, 0xe9, 0x1b, 0x34, 0x93, 0xd5, 0xbb, 0x98, 0xfa, 0xed, 0x49,
+ 0xe8, 0x5f, 0x13, 0x0f, 0xc8, 0xa4, 0x59, 0xb7 };
+
+/* "Entropy" from buffer */
+static size_t test_offset;
+static int hmac_drbg_self_test_entropy( void *data,
+ unsigned char *buf, size_t len )
+{
+ const unsigned char *p = data;
+ memcpy( buf, p + test_offset, len );
+ test_offset += len;
+ return( 0 );
+}
+
+#define CHK( c ) if( (c) != 0 ) \
+ { \
+ if( verbose != 0 ) \
+ mbedcrypto_printf( "failed\n" ); \
+ return( 1 ); \
+ }
+
+/*
+ * Checkup routine for HMAC_DRBG with SHA-1
+ */
+int mbedcrypto_hmac_drbg_self_test( int verbose )
+{
+ mbedcrypto_hmac_drbg_context ctx;
+ unsigned char buf[OUTPUT_LEN];
+ const mbedcrypto_md_info_t *md_info = mbedcrypto_md_info_from_type( MBEDCRYPTO_MD_SHA1 );
+
+ mbedcrypto_hmac_drbg_init( &ctx );
+
+ /*
+ * PR = True
+ */
+ if( verbose != 0 )
+ mbedcrypto_printf( " HMAC_DRBG (PR = True) : " );
+
+ test_offset = 0;
+ CHK( mbedcrypto_hmac_drbg_seed( &ctx, md_info,
+ hmac_drbg_self_test_entropy, (void *) entropy_pr,
+ NULL, 0 ) );
+ mbedcrypto_hmac_drbg_set_prediction_resistance( &ctx, MBEDCRYPTO_HMAC_DRBG_PR_ON );
+ CHK( mbedcrypto_hmac_drbg_random( &ctx, buf, OUTPUT_LEN ) );
+ CHK( mbedcrypto_hmac_drbg_random( &ctx, buf, OUTPUT_LEN ) );
+ CHK( memcmp( buf, result_pr, OUTPUT_LEN ) );
+ mbedcrypto_hmac_drbg_free( &ctx );
+
+ mbedcrypto_hmac_drbg_free( &ctx );
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+
+ /*
+ * PR = False
+ */
+ if( verbose != 0 )
+ mbedcrypto_printf( " HMAC_DRBG (PR = False) : " );
+
+ mbedcrypto_hmac_drbg_init( &ctx );
+
+ test_offset = 0;
+ CHK( mbedcrypto_hmac_drbg_seed( &ctx, md_info,
+ hmac_drbg_self_test_entropy, (void *) entropy_nopr,
+ NULL, 0 ) );
+ CHK( mbedcrypto_hmac_drbg_reseed( &ctx, NULL, 0 ) );
+ CHK( mbedcrypto_hmac_drbg_random( &ctx, buf, OUTPUT_LEN ) );
+ CHK( mbedcrypto_hmac_drbg_random( &ctx, buf, OUTPUT_LEN ) );
+ CHK( memcmp( buf, result_nopr, OUTPUT_LEN ) );
+ mbedcrypto_hmac_drbg_free( &ctx );
+
+ mbedcrypto_hmac_drbg_free( &ctx );
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "\n" );
+
+ return( 0 );
+}
+#endif /* MBEDCRYPTO_SHA1_C */
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#endif /* MBEDCRYPTO_HMAC_DRBG_C */
diff --git a/library/md.c b/library/md.c
new file mode 100644
index 0000000..143efa5
--- /dev/null
+++ b/library/md.c
@@ -0,0 +1,475 @@
+/**
+ * \file mbedcrypto_md.c
+ *
+ * \brief Generic message digest wrapper for Mbed Crypto
+ *
+ * \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 Crypto (https://tls.mbed.org)
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_MD_C)
+
+#include "mbedcrypto/md.h"
+#include "mbedcrypto/md_internal.h"
+#include "mbedcrypto/platform_util.h"
+
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#include <stdlib.h>
+#define mbedcrypto_calloc calloc
+#define mbedcrypto_free free
+#endif
+
+#include <string.h>
+
+#if defined(MBEDCRYPTO_FS_IO)
+#include <stdio.h>
+#endif
+
+/*
+ * Reminder: update profiles in x509_crt.c when adding a new hash!
+ */
+static const int supported_digests[] = {
+
+#if defined(MBEDCRYPTO_SHA512_C)
+ MBEDCRYPTO_MD_SHA512,
+ MBEDCRYPTO_MD_SHA384,
+#endif
+
+#if defined(MBEDCRYPTO_SHA256_C)
+ MBEDCRYPTO_MD_SHA256,
+ MBEDCRYPTO_MD_SHA224,
+#endif
+
+#if defined(MBEDCRYPTO_SHA1_C)
+ MBEDCRYPTO_MD_SHA1,
+#endif
+
+#if defined(MBEDCRYPTO_RIPEMD160_C)
+ MBEDCRYPTO_MD_RIPEMD160,
+#endif
+
+#if defined(MBEDCRYPTO_MD5_C)
+ MBEDCRYPTO_MD_MD5,
+#endif
+
+#if defined(MBEDCRYPTO_MD4_C)
+ MBEDCRYPTO_MD_MD4,
+#endif
+
+#if defined(MBEDCRYPTO_MD2_C)
+ MBEDCRYPTO_MD_MD2,
+#endif
+
+ MBEDCRYPTO_MD_NONE
+};
+
+const int *mbedcrypto_md_list( void )
+{
+ return( supported_digests );
+}
+
+const mbedcrypto_md_info_t *mbedcrypto_md_info_from_string( const char *md_name )
+{
+ if( NULL == md_name )
+ return( NULL );
+
+ /* Get the appropriate digest information */
+#if defined(MBEDCRYPTO_MD2_C)
+ if( !strcmp( "MD2", md_name ) )
+ return mbedcrypto_md_info_from_type( MBEDCRYPTO_MD_MD2 );
+#endif
+#if defined(MBEDCRYPTO_MD4_C)
+ if( !strcmp( "MD4", md_name ) )
+ return mbedcrypto_md_info_from_type( MBEDCRYPTO_MD_MD4 );
+#endif
+#if defined(MBEDCRYPTO_MD5_C)
+ if( !strcmp( "MD5", md_name ) )
+ return mbedcrypto_md_info_from_type( MBEDCRYPTO_MD_MD5 );
+#endif
+#if defined(MBEDCRYPTO_RIPEMD160_C)
+ if( !strcmp( "RIPEMD160", md_name ) )
+ return mbedcrypto_md_info_from_type( MBEDCRYPTO_MD_RIPEMD160 );
+#endif
+#if defined(MBEDCRYPTO_SHA1_C)
+ if( !strcmp( "SHA1", md_name ) || !strcmp( "SHA", md_name ) )
+ return mbedcrypto_md_info_from_type( MBEDCRYPTO_MD_SHA1 );
+#endif
+#if defined(MBEDCRYPTO_SHA256_C)
+ if( !strcmp( "SHA224", md_name ) )
+ return mbedcrypto_md_info_from_type( MBEDCRYPTO_MD_SHA224 );
+ if( !strcmp( "SHA256", md_name ) )
+ return mbedcrypto_md_info_from_type( MBEDCRYPTO_MD_SHA256 );
+#endif
+#if defined(MBEDCRYPTO_SHA512_C)
+ if( !strcmp( "SHA384", md_name ) )
+ return mbedcrypto_md_info_from_type( MBEDCRYPTO_MD_SHA384 );
+ if( !strcmp( "SHA512", md_name ) )
+ return mbedcrypto_md_info_from_type( MBEDCRYPTO_MD_SHA512 );
+#endif
+ return( NULL );
+}
+
+const mbedcrypto_md_info_t *mbedcrypto_md_info_from_type( mbedcrypto_md_type_t md_type )
+{
+ switch( md_type )
+ {
+#if defined(MBEDCRYPTO_MD2_C)
+ case MBEDCRYPTO_MD_MD2:
+ return( &mbedcrypto_md2_info );
+#endif
+#if defined(MBEDCRYPTO_MD4_C)
+ case MBEDCRYPTO_MD_MD4:
+ return( &mbedcrypto_md4_info );
+#endif
+#if defined(MBEDCRYPTO_MD5_C)
+ case MBEDCRYPTO_MD_MD5:
+ return( &mbedcrypto_md5_info );
+#endif
+#if defined(MBEDCRYPTO_RIPEMD160_C)
+ case MBEDCRYPTO_MD_RIPEMD160:
+ return( &mbedcrypto_ripemd160_info );
+#endif
+#if defined(MBEDCRYPTO_SHA1_C)
+ case MBEDCRYPTO_MD_SHA1:
+ return( &mbedcrypto_sha1_info );
+#endif
+#if defined(MBEDCRYPTO_SHA256_C)
+ case MBEDCRYPTO_MD_SHA224:
+ return( &mbedcrypto_sha224_info );
+ case MBEDCRYPTO_MD_SHA256:
+ return( &mbedcrypto_sha256_info );
+#endif
+#if defined(MBEDCRYPTO_SHA512_C)
+ case MBEDCRYPTO_MD_SHA384:
+ return( &mbedcrypto_sha384_info );
+ case MBEDCRYPTO_MD_SHA512:
+ return( &mbedcrypto_sha512_info );
+#endif
+ default:
+ return( NULL );
+ }
+}
+
+void mbedcrypto_md_init( mbedcrypto_md_context_t *ctx )
+{
+ memset( ctx, 0, sizeof( mbedcrypto_md_context_t ) );
+}
+
+void mbedcrypto_md_free( mbedcrypto_md_context_t *ctx )
+{
+ if( ctx == NULL || ctx->md_info == NULL )
+ return;
+
+ if( ctx->md_ctx != NULL )
+ ctx->md_info->ctx_free_func( ctx->md_ctx );
+
+ if( ctx->hmac_ctx != NULL )
+ {
+ mbedcrypto_platform_zeroize( ctx->hmac_ctx,
+ 2 * ctx->md_info->block_size );
+ mbedcrypto_free( ctx->hmac_ctx );
+ }
+
+ mbedcrypto_platform_zeroize( ctx, sizeof( mbedcrypto_md_context_t ) );
+}
+
+int mbedcrypto_md_clone( mbedcrypto_md_context_t *dst,
+ const mbedcrypto_md_context_t *src )
+{
+ if( dst == NULL || dst->md_info == NULL ||
+ src == NULL || src->md_info == NULL ||
+ dst->md_info != src->md_info )
+ {
+ return( MBEDCRYPTO_ERR_MD_BAD_INPUT_DATA );
+ }
+
+ dst->md_info->clone_func( dst->md_ctx, src->md_ctx );
+
+ return( 0 );
+}
+
+#if ! defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+int mbedcrypto_md_init_ctx( mbedcrypto_md_context_t *ctx, const mbedcrypto_md_info_t *md_info )
+{
+ return mbedcrypto_md_setup( ctx, md_info, 1 );
+}
+#endif
+
+int mbedcrypto_md_setup( mbedcrypto_md_context_t *ctx, const mbedcrypto_md_info_t *md_info, int hmac )
+{
+ if( md_info == NULL || ctx == NULL )
+ return( MBEDCRYPTO_ERR_MD_BAD_INPUT_DATA );
+
+ if( ( ctx->md_ctx = md_info->ctx_alloc_func() ) == NULL )
+ return( MBEDCRYPTO_ERR_MD_ALLOC_FAILED );
+
+ if( hmac != 0 )
+ {
+ ctx->hmac_ctx = mbedcrypto_calloc( 2, md_info->block_size );
+ if( ctx->hmac_ctx == NULL )
+ {
+ md_info->ctx_free_func( ctx->md_ctx );
+ return( MBEDCRYPTO_ERR_MD_ALLOC_FAILED );
+ }
+ }
+
+ ctx->md_info = md_info;
+
+ return( 0 );
+}
+
+int mbedcrypto_md_starts( mbedcrypto_md_context_t *ctx )
+{
+ if( ctx == NULL || ctx->md_info == NULL )
+ return( MBEDCRYPTO_ERR_MD_BAD_INPUT_DATA );
+
+ return( ctx->md_info->starts_func( ctx->md_ctx ) );
+}
+
+int mbedcrypto_md_update( mbedcrypto_md_context_t *ctx, const unsigned char *input, size_t ilen )
+{
+ if( ctx == NULL || ctx->md_info == NULL )
+ return( MBEDCRYPTO_ERR_MD_BAD_INPUT_DATA );
+
+ return( ctx->md_info->update_func( ctx->md_ctx, input, ilen ) );
+}
+
+int mbedcrypto_md_finish( mbedcrypto_md_context_t *ctx, unsigned char *output )
+{
+ if( ctx == NULL || ctx->md_info == NULL )
+ return( MBEDCRYPTO_ERR_MD_BAD_INPUT_DATA );
+
+ return( ctx->md_info->finish_func( ctx->md_ctx, output ) );
+}
+
+int mbedcrypto_md( const mbedcrypto_md_info_t *md_info, const unsigned char *input, size_t ilen,
+ unsigned char *output )
+{
+ if( md_info == NULL )
+ return( MBEDCRYPTO_ERR_MD_BAD_INPUT_DATA );
+
+ return( md_info->digest_func( input, ilen, output ) );
+}
+
+#if defined(MBEDCRYPTO_FS_IO)
+int mbedcrypto_md_file( const mbedcrypto_md_info_t *md_info, const char *path, unsigned char *output )
+{
+ int ret;
+ FILE *f;
+ size_t n;
+ mbedcrypto_md_context_t ctx;
+ unsigned char buf[1024];
+
+ if( md_info == NULL )
+ return( MBEDCRYPTO_ERR_MD_BAD_INPUT_DATA );
+
+ if( ( f = fopen( path, "rb" ) ) == NULL )
+ return( MBEDCRYPTO_ERR_MD_FILE_IO_ERROR );
+
+ mbedcrypto_md_init( &ctx );
+
+ if( ( ret = mbedcrypto_md_setup( &ctx, md_info, 0 ) ) != 0 )
+ goto cleanup;
+
+ if( ( ret = md_info->starts_func( ctx.md_ctx ) ) != 0 )
+ goto cleanup;
+
+ while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
+ if( ( ret = md_info->update_func( ctx.md_ctx, buf, n ) ) != 0 )
+ goto cleanup;
+
+ if( ferror( f ) != 0 )
+ ret = MBEDCRYPTO_ERR_MD_FILE_IO_ERROR;
+ else
+ ret = md_info->finish_func( ctx.md_ctx, output );
+
+cleanup:
+ mbedcrypto_platform_zeroize( buf, sizeof( buf ) );
+ fclose( f );
+ mbedcrypto_md_free( &ctx );
+
+ return( ret );
+}
+#endif /* MBEDCRYPTO_FS_IO */
+
+int mbedcrypto_md_hmac_starts( mbedcrypto_md_context_t *ctx, const unsigned char *key, size_t keylen )
+{
+ int ret;
+ unsigned char sum[MBEDCRYPTO_MD_MAX_SIZE];
+ unsigned char *ipad, *opad;
+ size_t i;
+
+ if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL )
+ return( MBEDCRYPTO_ERR_MD_BAD_INPUT_DATA );
+
+ if( keylen > (size_t) ctx->md_info->block_size )
+ {
+ if( ( ret = ctx->md_info->starts_func( ctx->md_ctx ) ) != 0 )
+ goto cleanup;
+ if( ( ret = ctx->md_info->update_func( ctx->md_ctx, key, keylen ) ) != 0 )
+ goto cleanup;
+ if( ( ret = ctx->md_info->finish_func( ctx->md_ctx, sum ) ) != 0 )
+ goto cleanup;
+
+ keylen = ctx->md_info->size;
+ key = sum;
+ }
+
+ ipad = (unsigned char *) ctx->hmac_ctx;
+ opad = (unsigned char *) ctx->hmac_ctx + ctx->md_info->block_size;
+
+ memset( ipad, 0x36, ctx->md_info->block_size );
+ memset( opad, 0x5C, ctx->md_info->block_size );
+
+ for( i = 0; i < keylen; i++ )
+ {
+ ipad[i] = (unsigned char)( ipad[i] ^ key[i] );
+ opad[i] = (unsigned char)( opad[i] ^ key[i] );
+ }
+
+ if( ( ret = ctx->md_info->starts_func( ctx->md_ctx ) ) != 0 )
+ goto cleanup;
+ if( ( ret = ctx->md_info->update_func( ctx->md_ctx, ipad,
+ ctx->md_info->block_size ) ) != 0 )
+ goto cleanup;
+
+cleanup:
+ mbedcrypto_platform_zeroize( sum, sizeof( sum ) );
+
+ return( ret );
+}
+
+int mbedcrypto_md_hmac_update( mbedcrypto_md_context_t *ctx, const unsigned char *input, size_t ilen )
+{
+ if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL )
+ return( MBEDCRYPTO_ERR_MD_BAD_INPUT_DATA );
+
+ return( ctx->md_info->update_func( ctx->md_ctx, input, ilen ) );
+}
+
+int mbedcrypto_md_hmac_finish( mbedcrypto_md_context_t *ctx, unsigned char *output )
+{
+ int ret;
+ unsigned char tmp[MBEDCRYPTO_MD_MAX_SIZE];
+ unsigned char *opad;
+
+ if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL )
+ return( MBEDCRYPTO_ERR_MD_BAD_INPUT_DATA );
+
+ opad = (unsigned char *) ctx->hmac_ctx + ctx->md_info->block_size;
+
+ if( ( ret = ctx->md_info->finish_func( ctx->md_ctx, tmp ) ) != 0 )
+ return( ret );
+ if( ( ret = ctx->md_info->starts_func( ctx->md_ctx ) ) != 0 )
+ return( ret );
+ if( ( ret = ctx->md_info->update_func( ctx->md_ctx, opad,
+ ctx->md_info->block_size ) ) != 0 )
+ return( ret );
+ if( ( ret = ctx->md_info->update_func( ctx->md_ctx, tmp,
+ ctx->md_info->size ) ) != 0 )
+ return( ret );
+ return( ctx->md_info->finish_func( ctx->md_ctx, output ) );
+}
+
+int mbedcrypto_md_hmac_reset( mbedcrypto_md_context_t *ctx )
+{
+ int ret;
+ unsigned char *ipad;
+
+ if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL )
+ return( MBEDCRYPTO_ERR_MD_BAD_INPUT_DATA );
+
+ ipad = (unsigned char *) ctx->hmac_ctx;
+
+ if( ( ret = ctx->md_info->starts_func( ctx->md_ctx ) ) != 0 )
+ return( ret );
+ return( ctx->md_info->update_func( ctx->md_ctx, ipad,
+ ctx->md_info->block_size ) );
+}
+
+int mbedcrypto_md_hmac( const mbedcrypto_md_info_t *md_info,
+ const unsigned char *key, size_t keylen,
+ const unsigned char *input, size_t ilen,
+ unsigned char *output )
+{
+ mbedcrypto_md_context_t ctx;
+ int ret;
+
+ if( md_info == NULL )
+ return( MBEDCRYPTO_ERR_MD_BAD_INPUT_DATA );
+
+ mbedcrypto_md_init( &ctx );
+
+ if( ( ret = mbedcrypto_md_setup( &ctx, md_info, 1 ) ) != 0 )
+ goto cleanup;
+
+ if( ( ret = mbedcrypto_md_hmac_starts( &ctx, key, keylen ) ) != 0 )
+ goto cleanup;
+ if( ( ret = mbedcrypto_md_hmac_update( &ctx, input, ilen ) ) != 0 )
+ goto cleanup;
+ if( ( ret = mbedcrypto_md_hmac_finish( &ctx, output ) ) != 0 )
+ goto cleanup;
+
+cleanup:
+ mbedcrypto_md_free( &ctx );
+
+ return( ret );
+}
+
+int mbedcrypto_md_process( mbedcrypto_md_context_t *ctx, const unsigned char *data )
+{
+ if( ctx == NULL || ctx->md_info == NULL )
+ return( MBEDCRYPTO_ERR_MD_BAD_INPUT_DATA );
+
+ return( ctx->md_info->process_func( ctx->md_ctx, data ) );
+}
+
+unsigned char mbedcrypto_md_get_size( const mbedcrypto_md_info_t *md_info )
+{
+ if( md_info == NULL )
+ return( 0 );
+
+ return md_info->size;
+}
+
+mbedcrypto_md_type_t mbedcrypto_md_get_type( const mbedcrypto_md_info_t *md_info )
+{
+ if( md_info == NULL )
+ return( MBEDCRYPTO_MD_NONE );
+
+ return md_info->type;
+}
+
+const char *mbedcrypto_md_get_name( const mbedcrypto_md_info_t *md_info )
+{
+ if( md_info == NULL )
+ return( NULL );
+
+ return md_info->name;
+}
+
+#endif /* MBEDCRYPTO_MD_C */
diff --git a/library/md2.c b/library/md2.c
new file mode 100644
index 0000000..ffccd0b
--- /dev/null
+++ b/library/md2.c
@@ -0,0 +1,363 @@
+/*
+ * RFC 1115/1319 compliant MD2 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 Crypto (https://tls.mbed.org)
+ */
+/*
+ * The MD2 algorithm was designed by Ron Rivest in 1989.
+ *
+ * http://www.ietf.org/rfc/rfc1115.txt
+ * http://www.ietf.org/rfc/rfc1319.txt
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_MD2_C)
+
+#include "mbedcrypto/md2.h"
+#include "mbedcrypto/platform_util.h"
+
+#include <string.h>
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#include <stdio.h>
+#define mbedcrypto_printf printf
+#endif /* MBEDCRYPTO_PLATFORM_C */
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#if !defined(MBEDCRYPTO_MD2_ALT)
+
+static const unsigned char PI_SUBST[256] =
+{
+ 0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36,
+ 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13, 0x62, 0xA7, 0x05, 0xF3,
+ 0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C,
+ 0x82, 0xCA, 0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16,
+ 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12, 0xBE, 0x4E,
+ 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E,
+ 0xBB, 0x2F, 0xEE, 0x7A, 0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2,
+ 0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21,
+ 0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E,
+ 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03, 0xFF, 0x19, 0x30, 0xB3,
+ 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56,
+ 0xAA, 0xC6, 0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6,
+ 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1, 0x45, 0x9D,
+ 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65,
+ 0xE6, 0x2D, 0xA8, 0x02, 0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0,
+ 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F,
+ 0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C,
+ 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26, 0x2C, 0x53, 0x0D, 0x6E,
+ 0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81,
+ 0x4D, 0x52, 0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA,
+ 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A, 0x78, 0x88,
+ 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE,
+ 0x3B, 0x00, 0x1D, 0x39, 0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58,
+ 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A,
+ 0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99,
+ 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14
+};
+
+void mbedcrypto_md2_init( mbedcrypto_md2_context *ctx )
+{
+ memset( ctx, 0, sizeof( mbedcrypto_md2_context ) );
+}
+
+void mbedcrypto_md2_free( mbedcrypto_md2_context *ctx )
+{
+ if( ctx == NULL )
+ return;
+
+ mbedcrypto_platform_zeroize( ctx, sizeof( mbedcrypto_md2_context ) );
+}
+
+void mbedcrypto_md2_clone( mbedcrypto_md2_context *dst,
+ const mbedcrypto_md2_context *src )
+{
+ *dst = *src;
+}
+
+/*
+ * MD2 context setup
+ */
+int mbedcrypto_md2_starts_ret( mbedcrypto_md2_context *ctx )
+{
+ memset( ctx->cksum, 0, 16 );
+ memset( ctx->state, 0, 46 );
+ memset( ctx->buffer, 0, 16 );
+ ctx->left = 0;
+
+ return( 0 );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_md2_starts( mbedcrypto_md2_context *ctx )
+{
+ mbedcrypto_md2_starts_ret( ctx );
+}
+#endif
+
+#if !defined(MBEDCRYPTO_MD2_PROCESS_ALT)
+int mbedcrypto_internal_md2_process( mbedcrypto_md2_context *ctx )
+{
+ int i, j;
+ unsigned char t = 0;
+
+ for( i = 0; i < 16; i++ )
+ {
+ ctx->state[i + 16] = ctx->buffer[i];
+ ctx->state[i + 32] =
+ (unsigned char)( ctx->buffer[i] ^ ctx->state[i]);
+ }
+
+ for( i = 0; i < 18; i++ )
+ {
+ for( j = 0; j < 48; j++ )
+ {
+ ctx->state[j] = (unsigned char)
+ ( ctx->state[j] ^ PI_SUBST[t] );
+ t = ctx->state[j];
+ }
+
+ t = (unsigned char)( t + i );
+ }
+
+ t = ctx->cksum[15];
+
+ for( i = 0; i < 16; i++ )
+ {
+ ctx->cksum[i] = (unsigned char)
+ ( ctx->cksum[i] ^ PI_SUBST[ctx->buffer[i] ^ t] );
+ t = ctx->cksum[i];
+ }
+
+ return( 0 );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_md2_process( mbedcrypto_md2_context *ctx )
+{
+ mbedcrypto_internal_md2_process( ctx );
+}
+#endif
+#endif /* !MBEDCRYPTO_MD2_PROCESS_ALT */
+
+/*
+ * MD2 process buffer
+ */
+int mbedcrypto_md2_update_ret( mbedcrypto_md2_context *ctx,
+ const unsigned char *input,
+ size_t ilen )
+{
+ int ret;
+ size_t fill;
+
+ while( ilen > 0 )
+ {
+ if( ilen > 16 - ctx->left )
+ fill = 16 - ctx->left;
+ else
+ fill = ilen;
+
+ memcpy( ctx->buffer + ctx->left, input, fill );
+
+ ctx->left += fill;
+ input += fill;
+ ilen -= fill;
+
+ if( ctx->left == 16 )
+ {
+ ctx->left = 0;
+ if( ( ret = mbedcrypto_internal_md2_process( ctx ) ) != 0 )
+ return( ret );
+ }
+ }
+
+ return( 0 );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_md2_update( mbedcrypto_md2_context *ctx,
+ const unsigned char *input,
+ size_t ilen )
+{
+ mbedcrypto_md2_update_ret( ctx, input, ilen );
+}
+#endif
+
+/*
+ * MD2 final digest
+ */
+int mbedcrypto_md2_finish_ret( mbedcrypto_md2_context *ctx,
+ unsigned char output[16] )
+{
+ int ret;
+ size_t i;
+ unsigned char x;
+
+ x = (unsigned char)( 16 - ctx->left );
+
+ for( i = ctx->left; i < 16; i++ )
+ ctx->buffer[i] = x;
+
+ if( ( ret = mbedcrypto_internal_md2_process( ctx ) ) != 0 )
+ return( ret );
+
+ memcpy( ctx->buffer, ctx->cksum, 16 );
+ if( ( ret = mbedcrypto_internal_md2_process( ctx ) ) != 0 )
+ return( ret );
+
+ memcpy( output, ctx->state, 16 );
+
+ return( 0 );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_md2_finish( mbedcrypto_md2_context *ctx,
+ unsigned char output[16] )
+{
+ mbedcrypto_md2_finish_ret( ctx, output );
+}
+#endif
+
+#endif /* !MBEDCRYPTO_MD2_ALT */
+
+/*
+ * output = MD2( input buffer )
+ */
+int mbedcrypto_md2_ret( const unsigned char *input,
+ size_t ilen,
+ unsigned char output[16] )
+{
+ int ret;
+ mbedcrypto_md2_context ctx;
+
+ mbedcrypto_md2_init( &ctx );
+
+ if( ( ret = mbedcrypto_md2_starts_ret( &ctx ) ) != 0 )
+ goto exit;
+
+ if( ( ret = mbedcrypto_md2_update_ret( &ctx, input, ilen ) ) != 0 )
+ goto exit;
+
+ if( ( ret = mbedcrypto_md2_finish_ret( &ctx, output ) ) != 0 )
+ goto exit;
+
+exit:
+ mbedcrypto_md2_free( &ctx );
+
+ return( ret );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_md2( const unsigned char *input,
+ size_t ilen,
+ unsigned char output[16] )
+{
+ mbedcrypto_md2_ret( input, ilen, output );
+}
+#endif
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+
+/*
+ * RFC 1319 test vectors
+ */
+static const unsigned char md2_test_str[7][81] =
+{
+ { "" },
+ { "a" },
+ { "abc" },
+ { "message digest" },
+ { "abcdefghijklmnopqrstuvwxyz" },
+ { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" },
+ { "12345678901234567890123456789012345678901234567890123456789012"
+ "345678901234567890" }
+};
+
+static const size_t md2_test_strlen[7] =
+{
+ 0, 1, 3, 14, 26, 62, 80
+};
+
+static const unsigned char md2_test_sum[7][16] =
+{
+ { 0x83, 0x50, 0xE5, 0xA3, 0xE2, 0x4C, 0x15, 0x3D,
+ 0xF2, 0x27, 0x5C, 0x9F, 0x80, 0x69, 0x27, 0x73 },
+ { 0x32, 0xEC, 0x01, 0xEC, 0x4A, 0x6D, 0xAC, 0x72,
+ 0xC0, 0xAB, 0x96, 0xFB, 0x34, 0xC0, 0xB5, 0xD1 },
+ { 0xDA, 0x85, 0x3B, 0x0D, 0x3F, 0x88, 0xD9, 0x9B,
+ 0x30, 0x28, 0x3A, 0x69, 0xE6, 0xDE, 0xD6, 0xBB },
+ { 0xAB, 0x4F, 0x49, 0x6B, 0xFB, 0x2A, 0x53, 0x0B,
+ 0x21, 0x9F, 0xF3, 0x30, 0x31, 0xFE, 0x06, 0xB0 },
+ { 0x4E, 0x8D, 0xDF, 0xF3, 0x65, 0x02, 0x92, 0xAB,
+ 0x5A, 0x41, 0x08, 0xC3, 0xAA, 0x47, 0x94, 0x0B },
+ { 0xDA, 0x33, 0xDE, 0xF2, 0xA4, 0x2D, 0xF1, 0x39,
+ 0x75, 0x35, 0x28, 0x46, 0xC3, 0x03, 0x38, 0xCD },
+ { 0xD5, 0x97, 0x6F, 0x79, 0xD8, 0x3D, 0x3A, 0x0D,
+ 0xC9, 0x80, 0x6C, 0x3C, 0x66, 0xF3, 0xEF, 0xD8 }
+};
+
+/*
+ * Checkup routine
+ */
+int mbedcrypto_md2_self_test( int verbose )
+{
+ int i, ret = 0;
+ unsigned char md2sum[16];
+
+ for( i = 0; i < 7; i++ )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( " MD2 test #%d: ", i + 1 );
+
+ ret = mbedcrypto_md2_ret( md2_test_str[i], md2_test_strlen[i], md2sum );
+ if( ret != 0 )
+ goto fail;
+
+ if( memcmp( md2sum, md2_test_sum[i], 16 ) != 0 )
+ {
+ ret = 1;
+ goto fail;
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "\n" );
+
+ return( 0 );
+
+fail:
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+
+ return( ret );
+}
+
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#endif /* MBEDCRYPTO_MD2_C */
diff --git a/library/md4.c b/library/md4.c
new file mode 100644
index 0000000..6fb9d68
--- /dev/null
+++ b/library/md4.c
@@ -0,0 +1,468 @@
+/*
+ * RFC 1186/1320 compliant MD4 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 Crypto (https://tls.mbed.org)
+ */
+/*
+ * The MD4 algorithm was designed by Ron Rivest in 1990.
+ *
+ * http://www.ietf.org/rfc/rfc1186.txt
+ * http://www.ietf.org/rfc/rfc1320.txt
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_MD4_C)
+
+#include "mbedcrypto/md4.h"
+#include "mbedcrypto/platform_util.h"
+
+#include <string.h>
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#include <stdio.h>
+#define mbedcrypto_printf printf
+#endif /* MBEDCRYPTO_PLATFORM_C */
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#if !defined(MBEDCRYPTO_MD4_ALT)
+
+/*
+ * 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
+
+void mbedcrypto_md4_init( mbedcrypto_md4_context *ctx )
+{
+ memset( ctx, 0, sizeof( mbedcrypto_md4_context ) );
+}
+
+void mbedcrypto_md4_free( mbedcrypto_md4_context *ctx )
+{
+ if( ctx == NULL )
+ return;
+
+ mbedcrypto_platform_zeroize( ctx, sizeof( mbedcrypto_md4_context ) );
+}
+
+void mbedcrypto_md4_clone( mbedcrypto_md4_context *dst,
+ const mbedcrypto_md4_context *src )
+{
+ *dst = *src;
+}
+
+/*
+ * MD4 context setup
+ */
+int mbedcrypto_md4_starts_ret( mbedcrypto_md4_context *ctx )
+{
+ ctx->total[0] = 0;
+ ctx->total[1] = 0;
+
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xEFCDAB89;
+ ctx->state[2] = 0x98BADCFE;
+ ctx->state[3] = 0x10325476;
+
+ return( 0 );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_md4_starts( mbedcrypto_md4_context *ctx )
+{
+ mbedcrypto_md4_starts_ret( ctx );
+}
+#endif
+
+#if !defined(MBEDCRYPTO_MD4_PROCESS_ALT)
+int mbedcrypto_internal_md4_process( mbedcrypto_md4_context *ctx,
+ const unsigned char data[64] )
+{
+ uint32_t X[16], A, B, C, D;
+
+ GET_UINT32_LE( X[ 0], data, 0 );
+ GET_UINT32_LE( X[ 1], data, 4 );
+ GET_UINT32_LE( X[ 2], data, 8 );
+ GET_UINT32_LE( X[ 3], data, 12 );
+ GET_UINT32_LE( X[ 4], data, 16 );
+ GET_UINT32_LE( X[ 5], data, 20 );
+ GET_UINT32_LE( X[ 6], data, 24 );
+ GET_UINT32_LE( X[ 7], data, 28 );
+ GET_UINT32_LE( X[ 8], data, 32 );
+ GET_UINT32_LE( X[ 9], data, 36 );
+ GET_UINT32_LE( X[10], data, 40 );
+ GET_UINT32_LE( X[11], data, 44 );
+ GET_UINT32_LE( X[12], data, 48 );
+ GET_UINT32_LE( X[13], data, 52 );
+ GET_UINT32_LE( X[14], data, 56 );
+ GET_UINT32_LE( X[15], data, 60 );
+
+#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
+
+ A = ctx->state[0];
+ B = ctx->state[1];
+ C = ctx->state[2];
+ D = ctx->state[3];
+
+#define F(x, y, z) ((x & y) | ((~x) & z))
+#define P(a,b,c,d,x,s) { a += F(b,c,d) + x; a = S(a,s); }
+
+ P( A, B, C, D, X[ 0], 3 );
+ P( D, A, B, C, X[ 1], 7 );
+ P( C, D, A, B, X[ 2], 11 );
+ P( B, C, D, A, X[ 3], 19 );
+ P( A, B, C, D, X[ 4], 3 );
+ P( D, A, B, C, X[ 5], 7 );
+ P( C, D, A, B, X[ 6], 11 );
+ P( B, C, D, A, X[ 7], 19 );
+ P( A, B, C, D, X[ 8], 3 );
+ P( D, A, B, C, X[ 9], 7 );
+ P( C, D, A, B, X[10], 11 );
+ P( B, C, D, A, X[11], 19 );
+ P( A, B, C, D, X[12], 3 );
+ P( D, A, B, C, X[13], 7 );
+ P( C, D, A, B, X[14], 11 );
+ P( B, C, D, A, X[15], 19 );
+
+#undef P
+#undef F
+
+#define F(x,y,z) ((x & y) | (x & z) | (y & z))
+#define P(a,b,c,d,x,s) { a += F(b,c,d) + x + 0x5A827999; a = S(a,s); }
+
+ P( A, B, C, D, X[ 0], 3 );
+ P( D, A, B, C, X[ 4], 5 );
+ P( C, D, A, B, X[ 8], 9 );
+ P( B, C, D, A, X[12], 13 );
+ P( A, B, C, D, X[ 1], 3 );
+ P( D, A, B, C, X[ 5], 5 );
+ P( C, D, A, B, X[ 9], 9 );
+ P( B, C, D, A, X[13], 13 );
+ P( A, B, C, D, X[ 2], 3 );
+ P( D, A, B, C, X[ 6], 5 );
+ P( C, D, A, B, X[10], 9 );
+ P( B, C, D, A, X[14], 13 );
+ P( A, B, C, D, X[ 3], 3 );
+ P( D, A, B, C, X[ 7], 5 );
+ P( C, D, A, B, X[11], 9 );
+ P( B, C, D, A, X[15], 13 );
+
+#undef P
+#undef F
+
+#define F(x,y,z) (x ^ y ^ z)
+#define P(a,b,c,d,x,s) { a += F(b,c,d) + x + 0x6ED9EBA1; a = S(a,s); }
+
+ P( A, B, C, D, X[ 0], 3 );
+ P( D, A, B, C, X[ 8], 9 );
+ P( C, D, A, B, X[ 4], 11 );
+ P( B, C, D, A, X[12], 15 );
+ P( A, B, C, D, X[ 2], 3 );
+ P( D, A, B, C, X[10], 9 );
+ P( C, D, A, B, X[ 6], 11 );
+ P( B, C, D, A, X[14], 15 );
+ P( A, B, C, D, X[ 1], 3 );
+ P( D, A, B, C, X[ 9], 9 );
+ P( C, D, A, B, X[ 5], 11 );
+ P( B, C, D, A, X[13], 15 );
+ P( A, B, C, D, X[ 3], 3 );
+ P( D, A, B, C, X[11], 9 );
+ P( C, D, A, B, X[ 7], 11 );
+ P( B, C, D, A, X[15], 15 );
+
+#undef F
+#undef P
+
+ ctx->state[0] += A;
+ ctx->state[1] += B;
+ ctx->state[2] += C;
+ ctx->state[3] += D;
+
+ return( 0 );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_md4_process( mbedcrypto_md4_context *ctx,
+ const unsigned char data[64] )
+{
+ mbedcrypto_internal_md4_process( ctx, data );
+}
+#endif
+#endif /* !MBEDCRYPTO_MD4_PROCESS_ALT */
+
+/*
+ * MD4 process buffer
+ */
+int mbedcrypto_md4_update_ret( mbedcrypto_md4_context *ctx,
+ const unsigned char *input,
+ size_t ilen )
+{
+ int ret;
+ size_t fill;
+ uint32_t left;
+
+ if( ilen == 0 )
+ return( 0 );
+
+ left = ctx->total[0] & 0x3F;
+ fill = 64 - left;
+
+ ctx->total[0] += (uint32_t) ilen;
+ ctx->total[0] &= 0xFFFFFFFF;
+
+ if( ctx->total[0] < (uint32_t) ilen )
+ ctx->total[1]++;
+
+ if( left && ilen >= fill )
+ {
+ memcpy( (void *) (ctx->buffer + left),
+ (void *) input, fill );
+
+ if( ( ret = mbedcrypto_internal_md4_process( ctx, ctx->buffer ) ) != 0 )
+ return( ret );
+
+ input += fill;
+ ilen -= fill;
+ left = 0;
+ }
+
+ while( ilen >= 64 )
+ {
+ if( ( ret = mbedcrypto_internal_md4_process( ctx, input ) ) != 0 )
+ return( ret );
+
+ input += 64;
+ ilen -= 64;
+ }
+
+ if( ilen > 0 )
+ {
+ memcpy( (void *) (ctx->buffer + left),
+ (void *) input, ilen );
+ }
+
+ return( 0 );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_md4_update( mbedcrypto_md4_context *ctx,
+ const unsigned char *input,
+ size_t ilen )
+{
+ mbedcrypto_md4_update_ret( ctx, input, ilen );
+}
+#endif
+
+static const unsigned char md4_padding[64] =
+{
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * MD4 final digest
+ */
+int mbedcrypto_md4_finish_ret( mbedcrypto_md4_context *ctx,
+ unsigned char output[16] )
+{
+ int ret;
+ uint32_t last, padn;
+ uint32_t high, low;
+ unsigned char msglen[8];
+
+ high = ( ctx->total[0] >> 29 )
+ | ( ctx->total[1] << 3 );
+ low = ( ctx->total[0] << 3 );
+
+ PUT_UINT32_LE( low, msglen, 0 );
+ PUT_UINT32_LE( high, msglen, 4 );
+
+ last = ctx->total[0] & 0x3F;
+ padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
+
+ ret = mbedcrypto_md4_update_ret( ctx, (unsigned char *)md4_padding, padn );
+ if( ret != 0 )
+ return( ret );
+
+ if( ( ret = mbedcrypto_md4_update_ret( ctx, msglen, 8 ) ) != 0 )
+ return( ret );
+
+
+ PUT_UINT32_LE( ctx->state[0], output, 0 );
+ PUT_UINT32_LE( ctx->state[1], output, 4 );
+ PUT_UINT32_LE( ctx->state[2], output, 8 );
+ PUT_UINT32_LE( ctx->state[3], output, 12 );
+
+ return( 0 );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_md4_finish( mbedcrypto_md4_context *ctx,
+ unsigned char output[16] )
+{
+ mbedcrypto_md4_finish_ret( ctx, output );
+}
+#endif
+
+#endif /* !MBEDCRYPTO_MD4_ALT */
+
+/*
+ * output = MD4( input buffer )
+ */
+int mbedcrypto_md4_ret( const unsigned char *input,
+ size_t ilen,
+ unsigned char output[16] )
+{
+ int ret;
+ mbedcrypto_md4_context ctx;
+
+ mbedcrypto_md4_init( &ctx );
+
+ if( ( ret = mbedcrypto_md4_starts_ret( &ctx ) ) != 0 )
+ goto exit;
+
+ if( ( ret = mbedcrypto_md4_update_ret( &ctx, input, ilen ) ) != 0 )
+ goto exit;
+
+ if( ( ret = mbedcrypto_md4_finish_ret( &ctx, output ) ) != 0 )
+ goto exit;
+
+exit:
+ mbedcrypto_md4_free( &ctx );
+
+ return( ret );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_md4( const unsigned char *input,
+ size_t ilen,
+ unsigned char output[16] )
+{
+ mbedcrypto_md4_ret( input, ilen, output );
+}
+#endif
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+
+/*
+ * RFC 1320 test vectors
+ */
+static const unsigned char md4_test_str[7][81] =
+{
+ { "" },
+ { "a" },
+ { "abc" },
+ { "message digest" },
+ { "abcdefghijklmnopqrstuvwxyz" },
+ { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" },
+ { "12345678901234567890123456789012345678901234567890123456789012"
+ "345678901234567890" }
+};
+
+static const size_t md4_test_strlen[7] =
+{
+ 0, 1, 3, 14, 26, 62, 80
+};
+
+static const unsigned char md4_test_sum[7][16] =
+{
+ { 0x31, 0xD6, 0xCF, 0xE0, 0xD1, 0x6A, 0xE9, 0x31,
+ 0xB7, 0x3C, 0x59, 0xD7, 0xE0, 0xC0, 0x89, 0xC0 },
+ { 0xBD, 0xE5, 0x2C, 0xB3, 0x1D, 0xE3, 0x3E, 0x46,
+ 0x24, 0x5E, 0x05, 0xFB, 0xDB, 0xD6, 0xFB, 0x24 },
+ { 0xA4, 0x48, 0x01, 0x7A, 0xAF, 0x21, 0xD8, 0x52,
+ 0x5F, 0xC1, 0x0A, 0xE8, 0x7A, 0xA6, 0x72, 0x9D },
+ { 0xD9, 0x13, 0x0A, 0x81, 0x64, 0x54, 0x9F, 0xE8,
+ 0x18, 0x87, 0x48, 0x06, 0xE1, 0xC7, 0x01, 0x4B },
+ { 0xD7, 0x9E, 0x1C, 0x30, 0x8A, 0xA5, 0xBB, 0xCD,
+ 0xEE, 0xA8, 0xED, 0x63, 0xDF, 0x41, 0x2D, 0xA9 },
+ { 0x04, 0x3F, 0x85, 0x82, 0xF2, 0x41, 0xDB, 0x35,
+ 0x1C, 0xE6, 0x27, 0xE1, 0x53, 0xE7, 0xF0, 0xE4 },
+ { 0xE3, 0x3B, 0x4D, 0xDC, 0x9C, 0x38, 0xF2, 0x19,
+ 0x9C, 0x3E, 0x7B, 0x16, 0x4F, 0xCC, 0x05, 0x36 }
+};
+
+/*
+ * Checkup routine
+ */
+int mbedcrypto_md4_self_test( int verbose )
+{
+ int i, ret = 0;
+ unsigned char md4sum[16];
+
+ for( i = 0; i < 7; i++ )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( " MD4 test #%d: ", i + 1 );
+
+ ret = mbedcrypto_md4_ret( md4_test_str[i], md4_test_strlen[i], md4sum );
+ if( ret != 0 )
+ goto fail;
+
+ if( memcmp( md4sum, md4_test_sum[i], 16 ) != 0 )
+ {
+ ret = 1;
+ goto fail;
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "\n" );
+
+ return( 0 );
+
+fail:
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+
+ return( ret );
+}
+
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#endif /* MBEDCRYPTO_MD4_C */
diff --git a/library/md5.c b/library/md5.c
new file mode 100644
index 0000000..b6a54c9
--- /dev/null
+++ b/library/md5.c
@@ -0,0 +1,481 @@
+/*
+ * RFC 1321 compliant MD5 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 Crypto (https://tls.mbed.org)
+ */
+/*
+ * The MD5 algorithm was designed by Ron Rivest in 1991.
+ *
+ * http://www.ietf.org/rfc/rfc1321.txt
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_MD5_C)
+
+#include "mbedcrypto/md5.h"
+#include "mbedcrypto/platform_util.h"
+
+#include <string.h>
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#include <stdio.h>
+#define mbedcrypto_printf printf
+#endif /* MBEDCRYPTO_PLATFORM_C */
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#if !defined(MBEDCRYPTO_MD5_ALT)
+
+/*
+ * 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
+
+void mbedcrypto_md5_init( mbedcrypto_md5_context *ctx )
+{
+ memset( ctx, 0, sizeof( mbedcrypto_md5_context ) );
+}
+
+void mbedcrypto_md5_free( mbedcrypto_md5_context *ctx )
+{
+ if( ctx == NULL )
+ return;
+
+ mbedcrypto_platform_zeroize( ctx, sizeof( mbedcrypto_md5_context ) );
+}
+
+void mbedcrypto_md5_clone( mbedcrypto_md5_context *dst,
+ const mbedcrypto_md5_context *src )
+{
+ *dst = *src;
+}
+
+/*
+ * MD5 context setup
+ */
+int mbedcrypto_md5_starts_ret( mbedcrypto_md5_context *ctx )
+{
+ ctx->total[0] = 0;
+ ctx->total[1] = 0;
+
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xEFCDAB89;
+ ctx->state[2] = 0x98BADCFE;
+ ctx->state[3] = 0x10325476;
+
+ return( 0 );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_md5_starts( mbedcrypto_md5_context *ctx )
+{
+ mbedcrypto_md5_starts_ret( ctx );
+}
+#endif
+
+#if !defined(MBEDCRYPTO_MD5_PROCESS_ALT)
+int mbedcrypto_internal_md5_process( mbedcrypto_md5_context *ctx,
+ const unsigned char data[64] )
+{
+ uint32_t X[16], A, B, C, D;
+
+ GET_UINT32_LE( X[ 0], data, 0 );
+ GET_UINT32_LE( X[ 1], data, 4 );
+ GET_UINT32_LE( X[ 2], data, 8 );
+ GET_UINT32_LE( X[ 3], data, 12 );
+ GET_UINT32_LE( X[ 4], data, 16 );
+ GET_UINT32_LE( X[ 5], data, 20 );
+ GET_UINT32_LE( X[ 6], data, 24 );
+ GET_UINT32_LE( X[ 7], data, 28 );
+ GET_UINT32_LE( X[ 8], data, 32 );
+ GET_UINT32_LE( X[ 9], data, 36 );
+ GET_UINT32_LE( X[10], data, 40 );
+ GET_UINT32_LE( X[11], data, 44 );
+ GET_UINT32_LE( X[12], data, 48 );
+ GET_UINT32_LE( X[13], data, 52 );
+ GET_UINT32_LE( X[14], data, 56 );
+ GET_UINT32_LE( X[15], data, 60 );
+
+#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
+
+#define P(a,b,c,d,k,s,t) \
+{ \
+ a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \
+}
+
+ A = ctx->state[0];
+ B = ctx->state[1];
+ C = ctx->state[2];
+ D = ctx->state[3];
+
+#define F(x,y,z) (z ^ (x & (y ^ z)))
+
+ P( A, B, C, D, 0, 7, 0xD76AA478 );
+ P( D, A, B, C, 1, 12, 0xE8C7B756 );
+ P( C, D, A, B, 2, 17, 0x242070DB );
+ P( B, C, D, A, 3, 22, 0xC1BDCEEE );
+ P( A, B, C, D, 4, 7, 0xF57C0FAF );
+ P( D, A, B, C, 5, 12, 0x4787C62A );
+ P( C, D, A, B, 6, 17, 0xA8304613 );
+ P( B, C, D, A, 7, 22, 0xFD469501 );
+ P( A, B, C, D, 8, 7, 0x698098D8 );
+ P( D, A, B, C, 9, 12, 0x8B44F7AF );
+ P( C, D, A, B, 10, 17, 0xFFFF5BB1 );
+ P( B, C, D, A, 11, 22, 0x895CD7BE );
+ P( A, B, C, D, 12, 7, 0x6B901122 );
+ P( D, A, B, C, 13, 12, 0xFD987193 );
+ P( C, D, A, B, 14, 17, 0xA679438E );
+ P( B, C, D, A, 15, 22, 0x49B40821 );
+
+#undef F
+
+#define F(x,y,z) (y ^ (z & (x ^ y)))
+
+ P( A, B, C, D, 1, 5, 0xF61E2562 );
+ P( D, A, B, C, 6, 9, 0xC040B340 );
+ P( C, D, A, B, 11, 14, 0x265E5A51 );
+ P( B, C, D, A, 0, 20, 0xE9B6C7AA );
+ P( A, B, C, D, 5, 5, 0xD62F105D );
+ P( D, A, B, C, 10, 9, 0x02441453 );
+ P( C, D, A, B, 15, 14, 0xD8A1E681 );
+ P( B, C, D, A, 4, 20, 0xE7D3FBC8 );
+ P( A, B, C, D, 9, 5, 0x21E1CDE6 );
+ P( D, A, B, C, 14, 9, 0xC33707D6 );
+ P( C, D, A, B, 3, 14, 0xF4D50D87 );
+ P( B, C, D, A, 8, 20, 0x455A14ED );
+ P( A, B, C, D, 13, 5, 0xA9E3E905 );
+ P( D, A, B, C, 2, 9, 0xFCEFA3F8 );
+ P( C, D, A, B, 7, 14, 0x676F02D9 );
+ P( B, C, D, A, 12, 20, 0x8D2A4C8A );
+
+#undef F
+
+#define F(x,y,z) (x ^ y ^ z)
+
+ P( A, B, C, D, 5, 4, 0xFFFA3942 );
+ P( D, A, B, C, 8, 11, 0x8771F681 );
+ P( C, D, A, B, 11, 16, 0x6D9D6122 );
+ P( B, C, D, A, 14, 23, 0xFDE5380C );
+ P( A, B, C, D, 1, 4, 0xA4BEEA44 );
+ P( D, A, B, C, 4, 11, 0x4BDECFA9 );
+ P( C, D, A, B, 7, 16, 0xF6BB4B60 );
+ P( B, C, D, A, 10, 23, 0xBEBFBC70 );
+ P( A, B, C, D, 13, 4, 0x289B7EC6 );
+ P( D, A, B, C, 0, 11, 0xEAA127FA );
+ P( C, D, A, B, 3, 16, 0xD4EF3085 );
+ P( B, C, D, A, 6, 23, 0x04881D05 );
+ P( A, B, C, D, 9, 4, 0xD9D4D039 );
+ P( D, A, B, C, 12, 11, 0xE6DB99E5 );
+ P( C, D, A, B, 15, 16, 0x1FA27CF8 );
+ P( B, C, D, A, 2, 23, 0xC4AC5665 );
+
+#undef F
+
+#define F(x,y,z) (y ^ (x | ~z))
+
+ P( A, B, C, D, 0, 6, 0xF4292244 );
+ P( D, A, B, C, 7, 10, 0x432AFF97 );
+ P( C, D, A, B, 14, 15, 0xAB9423A7 );
+ P( B, C, D, A, 5, 21, 0xFC93A039 );
+ P( A, B, C, D, 12, 6, 0x655B59C3 );
+ P( D, A, B, C, 3, 10, 0x8F0CCC92 );
+ P( C, D, A, B, 10, 15, 0xFFEFF47D );
+ P( B, C, D, A, 1, 21, 0x85845DD1 );
+ P( A, B, C, D, 8, 6, 0x6FA87E4F );
+ P( D, A, B, C, 15, 10, 0xFE2CE6E0 );
+ P( C, D, A, B, 6, 15, 0xA3014314 );
+ P( B, C, D, A, 13, 21, 0x4E0811A1 );
+ P( A, B, C, D, 4, 6, 0xF7537E82 );
+ P( D, A, B, C, 11, 10, 0xBD3AF235 );
+ P( C, D, A, B, 2, 15, 0x2AD7D2BB );
+ P( B, C, D, A, 9, 21, 0xEB86D391 );
+
+#undef F
+
+ ctx->state[0] += A;
+ ctx->state[1] += B;
+ ctx->state[2] += C;
+ ctx->state[3] += D;
+
+ return( 0 );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_md5_process( mbedcrypto_md5_context *ctx,
+ const unsigned char data[64] )
+{
+ mbedcrypto_internal_md5_process( ctx, data );
+}
+#endif
+#endif /* !MBEDCRYPTO_MD5_PROCESS_ALT */
+
+/*
+ * MD5 process buffer
+ */
+int mbedcrypto_md5_update_ret( mbedcrypto_md5_context *ctx,
+ const unsigned char *input,
+ size_t ilen )
+{
+ int ret;
+ size_t fill;
+ uint32_t left;
+
+ if( ilen == 0 )
+ return( 0 );
+
+ left = ctx->total[0] & 0x3F;
+ fill = 64 - left;
+
+ ctx->total[0] += (uint32_t) ilen;
+ ctx->total[0] &= 0xFFFFFFFF;
+
+ if( ctx->total[0] < (uint32_t) ilen )
+ ctx->total[1]++;
+
+ if( left && ilen >= fill )
+ {
+ memcpy( (void *) (ctx->buffer + left), input, fill );
+ if( ( ret = mbedcrypto_internal_md5_process( ctx, ctx->buffer ) ) != 0 )
+ return( ret );
+
+ input += fill;
+ ilen -= fill;
+ left = 0;
+ }
+
+ while( ilen >= 64 )
+ {
+ if( ( ret = mbedcrypto_internal_md5_process( ctx, input ) ) != 0 )
+ return( ret );
+
+ input += 64;
+ ilen -= 64;
+ }
+
+ if( ilen > 0 )
+ {
+ memcpy( (void *) (ctx->buffer + left), input, ilen );
+ }
+
+ return( 0 );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_md5_update( mbedcrypto_md5_context *ctx,
+ const unsigned char *input,
+ size_t ilen )
+{
+ mbedcrypto_md5_update_ret( ctx, input, ilen );
+}
+#endif
+
+static const unsigned char md5_padding[64] =
+{
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * MD5 final digest
+ */
+int mbedcrypto_md5_finish_ret( mbedcrypto_md5_context *ctx,
+ unsigned char output[16] )
+{
+ int ret;
+ uint32_t last, padn;
+ uint32_t high, low;
+ unsigned char msglen[8];
+
+ high = ( ctx->total[0] >> 29 )
+ | ( ctx->total[1] << 3 );
+ low = ( ctx->total[0] << 3 );
+
+ PUT_UINT32_LE( low, msglen, 0 );
+ PUT_UINT32_LE( high, msglen, 4 );
+
+ last = ctx->total[0] & 0x3F;
+ padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
+
+ if( ( ret = mbedcrypto_md5_update_ret( ctx, md5_padding, padn ) ) != 0 )
+ return( ret );
+
+ if( ( ret = mbedcrypto_md5_update_ret( ctx, msglen, 8 ) ) != 0 )
+ return( ret );
+
+ PUT_UINT32_LE( ctx->state[0], output, 0 );
+ PUT_UINT32_LE( ctx->state[1], output, 4 );
+ PUT_UINT32_LE( ctx->state[2], output, 8 );
+ PUT_UINT32_LE( ctx->state[3], output, 12 );
+
+ return( 0 );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_md5_finish( mbedcrypto_md5_context *ctx,
+ unsigned char output[16] )
+{
+ mbedcrypto_md5_finish_ret( ctx, output );
+}
+#endif
+
+#endif /* !MBEDCRYPTO_MD5_ALT */
+
+/*
+ * output = MD5( input buffer )
+ */
+int mbedcrypto_md5_ret( const unsigned char *input,
+ size_t ilen,
+ unsigned char output[16] )
+{
+ int ret;
+ mbedcrypto_md5_context ctx;
+
+ mbedcrypto_md5_init( &ctx );
+
+ if( ( ret = mbedcrypto_md5_starts_ret( &ctx ) ) != 0 )
+ goto exit;
+
+ if( ( ret = mbedcrypto_md5_update_ret( &ctx, input, ilen ) ) != 0 )
+ goto exit;
+
+ if( ( ret = mbedcrypto_md5_finish_ret( &ctx, output ) ) != 0 )
+ goto exit;
+
+exit:
+ mbedcrypto_md5_free( &ctx );
+
+ return( ret );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_md5( const unsigned char *input,
+ size_t ilen,
+ unsigned char output[16] )
+{
+ mbedcrypto_md5_ret( input, ilen, output );
+}
+#endif
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+/*
+ * RFC 1321 test vectors
+ */
+static const unsigned char md5_test_buf[7][81] =
+{
+ { "" },
+ { "a" },
+ { "abc" },
+ { "message digest" },
+ { "abcdefghijklmnopqrstuvwxyz" },
+ { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" },
+ { "12345678901234567890123456789012345678901234567890123456789012"
+ "345678901234567890" }
+};
+
+static const size_t md5_test_buflen[7] =
+{
+ 0, 1, 3, 14, 26, 62, 80
+};
+
+static const unsigned char md5_test_sum[7][16] =
+{
+ { 0xD4, 0x1D, 0x8C, 0xD9, 0x8F, 0x00, 0xB2, 0x04,
+ 0xE9, 0x80, 0x09, 0x98, 0xEC, 0xF8, 0x42, 0x7E },
+ { 0x0C, 0xC1, 0x75, 0xB9, 0xC0, 0xF1, 0xB6, 0xA8,
+ 0x31, 0xC3, 0x99, 0xE2, 0x69, 0x77, 0x26, 0x61 },
+ { 0x90, 0x01, 0x50, 0x98, 0x3C, 0xD2, 0x4F, 0xB0,
+ 0xD6, 0x96, 0x3F, 0x7D, 0x28, 0xE1, 0x7F, 0x72 },
+ { 0xF9, 0x6B, 0x69, 0x7D, 0x7C, 0xB7, 0x93, 0x8D,
+ 0x52, 0x5A, 0x2F, 0x31, 0xAA, 0xF1, 0x61, 0xD0 },
+ { 0xC3, 0xFC, 0xD3, 0xD7, 0x61, 0x92, 0xE4, 0x00,
+ 0x7D, 0xFB, 0x49, 0x6C, 0xCA, 0x67, 0xE1, 0x3B },
+ { 0xD1, 0x74, 0xAB, 0x98, 0xD2, 0x77, 0xD9, 0xF5,
+ 0xA5, 0x61, 0x1C, 0x2C, 0x9F, 0x41, 0x9D, 0x9F },
+ { 0x57, 0xED, 0xF4, 0xA2, 0x2B, 0xE3, 0xC9, 0x55,
+ 0xAC, 0x49, 0xDA, 0x2E, 0x21, 0x07, 0xB6, 0x7A }
+};
+
+/*
+ * Checkup routine
+ */
+int mbedcrypto_md5_self_test( int verbose )
+{
+ int i, ret = 0;
+ unsigned char md5sum[16];
+
+ for( i = 0; i < 7; i++ )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( " MD5 test #%d: ", i + 1 );
+
+ ret = mbedcrypto_md5_ret( md5_test_buf[i], md5_test_buflen[i], md5sum );
+ if( ret != 0 )
+ goto fail;
+
+ if( memcmp( md5sum, md5_test_sum[i], 16 ) != 0 )
+ {
+ ret = 1;
+ goto fail;
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "\n" );
+
+ return( 0 );
+
+fail:
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+
+ return( ret );
+}
+
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#endif /* MBEDCRYPTO_MD5_C */
diff --git a/library/md_wrap.c b/library/md_wrap.c
new file mode 100644
index 0000000..d4797c7
--- /dev/null
+++ b/library/md_wrap.c
@@ -0,0 +1,586 @@
+/**
+ * \file md_wrap.c
+ *
+ * \brief Generic message digest wrapper for Mbed Crypto
+ *
+ * \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 Crypto (https://tls.mbed.org)
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_MD_C)
+
+#include "mbedcrypto/md_internal.h"
+
+#if defined(MBEDCRYPTO_MD2_C)
+#include "mbedcrypto/md2.h"
+#endif
+
+#if defined(MBEDCRYPTO_MD4_C)
+#include "mbedcrypto/md4.h"
+#endif
+
+#if defined(MBEDCRYPTO_MD5_C)
+#include "mbedcrypto/md5.h"
+#endif
+
+#if defined(MBEDCRYPTO_RIPEMD160_C)
+#include "mbedcrypto/ripemd160.h"
+#endif
+
+#if defined(MBEDCRYPTO_SHA1_C)
+#include "mbedcrypto/sha1.h"
+#endif
+
+#if defined(MBEDCRYPTO_SHA256_C)
+#include "mbedcrypto/sha256.h"
+#endif
+
+#if defined(MBEDCRYPTO_SHA512_C)
+#include "mbedcrypto/sha512.h"
+#endif
+
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#include <stdlib.h>
+#define mbedcrypto_calloc calloc
+#define mbedcrypto_free free
+#endif
+
+#if defined(MBEDCRYPTO_MD2_C)
+
+static int md2_starts_wrap( void *ctx )
+{
+ return( mbedcrypto_md2_starts_ret( (mbedcrypto_md2_context *) ctx ) );
+}
+
+static int md2_update_wrap( void *ctx, const unsigned char *input,
+ size_t ilen )
+{
+ return( mbedcrypto_md2_update_ret( (mbedcrypto_md2_context *) ctx, input, ilen ) );
+}
+
+static int md2_finish_wrap( void *ctx, unsigned char *output )
+{
+ return( mbedcrypto_md2_finish_ret( (mbedcrypto_md2_context *) ctx, output ) );
+}
+
+static void *md2_ctx_alloc( void )
+{
+ void *ctx = mbedcrypto_calloc( 1, sizeof( mbedcrypto_md2_context ) );
+
+ if( ctx != NULL )
+ mbedcrypto_md2_init( (mbedcrypto_md2_context *) ctx );
+
+ return( ctx );
+}
+
+static void md2_ctx_free( void *ctx )
+{
+ mbedcrypto_md2_free( (mbedcrypto_md2_context *) ctx );
+ mbedcrypto_free( ctx );
+}
+
+static void md2_clone_wrap( void *dst, const void *src )
+{
+ mbedcrypto_md2_clone( (mbedcrypto_md2_context *) dst,
+ (const mbedcrypto_md2_context *) src );
+}
+
+static int md2_process_wrap( void *ctx, const unsigned char *data )
+{
+ ((void) data);
+
+ return( mbedcrypto_internal_md2_process( (mbedcrypto_md2_context *) ctx ) );
+}
+
+const mbedcrypto_md_info_t mbedcrypto_md2_info = {
+ MBEDCRYPTO_MD_MD2,
+ "MD2",
+ 16,
+ 16,
+ md2_starts_wrap,
+ md2_update_wrap,
+ md2_finish_wrap,
+ mbedcrypto_md2_ret,
+ md2_ctx_alloc,
+ md2_ctx_free,
+ md2_clone_wrap,
+ md2_process_wrap,
+};
+
+#endif /* MBEDCRYPTO_MD2_C */
+
+#if defined(MBEDCRYPTO_MD4_C)
+
+static int md4_starts_wrap( void *ctx )
+{
+ return( mbedcrypto_md4_starts_ret( (mbedcrypto_md4_context *) ctx ) );
+}
+
+static int md4_update_wrap( void *ctx, const unsigned char *input,
+ size_t ilen )
+{
+ return( mbedcrypto_md4_update_ret( (mbedcrypto_md4_context *) ctx, input, ilen ) );
+}
+
+static int md4_finish_wrap( void *ctx, unsigned char *output )
+{
+ return( mbedcrypto_md4_finish_ret( (mbedcrypto_md4_context *) ctx, output ) );
+}
+
+static void *md4_ctx_alloc( void )
+{
+ void *ctx = mbedcrypto_calloc( 1, sizeof( mbedcrypto_md4_context ) );
+
+ if( ctx != NULL )
+ mbedcrypto_md4_init( (mbedcrypto_md4_context *) ctx );
+
+ return( ctx );
+}
+
+static void md4_ctx_free( void *ctx )
+{
+ mbedcrypto_md4_free( (mbedcrypto_md4_context *) ctx );
+ mbedcrypto_free( ctx );
+}
+
+static void md4_clone_wrap( void *dst, const void *src )
+{
+ mbedcrypto_md4_clone( (mbedcrypto_md4_context *) dst,
+ (const mbedcrypto_md4_context *) src );
+}
+
+static int md4_process_wrap( void *ctx, const unsigned char *data )
+{
+ return( mbedcrypto_internal_md4_process( (mbedcrypto_md4_context *) ctx, data ) );
+}
+
+const mbedcrypto_md_info_t mbedcrypto_md4_info = {
+ MBEDCRYPTO_MD_MD4,
+ "MD4",
+ 16,
+ 64,
+ md4_starts_wrap,
+ md4_update_wrap,
+ md4_finish_wrap,
+ mbedcrypto_md4_ret,
+ md4_ctx_alloc,
+ md4_ctx_free,
+ md4_clone_wrap,
+ md4_process_wrap,
+};
+
+#endif /* MBEDCRYPTO_MD4_C */
+
+#if defined(MBEDCRYPTO_MD5_C)
+
+static int md5_starts_wrap( void *ctx )
+{
+ return( mbedcrypto_md5_starts_ret( (mbedcrypto_md5_context *) ctx ) );
+}
+
+static int md5_update_wrap( void *ctx, const unsigned char *input,
+ size_t ilen )
+{
+ return( mbedcrypto_md5_update_ret( (mbedcrypto_md5_context *) ctx, input, ilen ) );
+}
+
+static int md5_finish_wrap( void *ctx, unsigned char *output )
+{
+ return( mbedcrypto_md5_finish_ret( (mbedcrypto_md5_context *) ctx, output ) );
+}
+
+static void *md5_ctx_alloc( void )
+{
+ void *ctx = mbedcrypto_calloc( 1, sizeof( mbedcrypto_md5_context ) );
+
+ if( ctx != NULL )
+ mbedcrypto_md5_init( (mbedcrypto_md5_context *) ctx );
+
+ return( ctx );
+}
+
+static void md5_ctx_free( void *ctx )
+{
+ mbedcrypto_md5_free( (mbedcrypto_md5_context *) ctx );
+ mbedcrypto_free( ctx );
+}
+
+static void md5_clone_wrap( void *dst, const void *src )
+{
+ mbedcrypto_md5_clone( (mbedcrypto_md5_context *) dst,
+ (const mbedcrypto_md5_context *) src );
+}
+
+static int md5_process_wrap( void *ctx, const unsigned char *data )
+{
+ return( mbedcrypto_internal_md5_process( (mbedcrypto_md5_context *) ctx, data ) );
+}
+
+const mbedcrypto_md_info_t mbedcrypto_md5_info = {
+ MBEDCRYPTO_MD_MD5,
+ "MD5",
+ 16,
+ 64,
+ md5_starts_wrap,
+ md5_update_wrap,
+ md5_finish_wrap,
+ mbedcrypto_md5_ret,
+ md5_ctx_alloc,
+ md5_ctx_free,
+ md5_clone_wrap,
+ md5_process_wrap,
+};
+
+#endif /* MBEDCRYPTO_MD5_C */
+
+#if defined(MBEDCRYPTO_RIPEMD160_C)
+
+static int ripemd160_starts_wrap( void *ctx )
+{
+ return( mbedcrypto_ripemd160_starts_ret( (mbedcrypto_ripemd160_context *) ctx ) );
+}
+
+static int ripemd160_update_wrap( void *ctx, const unsigned char *input,
+ size_t ilen )
+{
+ return( mbedcrypto_ripemd160_update_ret( (mbedcrypto_ripemd160_context *) ctx,
+ input, ilen ) );
+}
+
+static int ripemd160_finish_wrap( void *ctx, unsigned char *output )
+{
+ return( mbedcrypto_ripemd160_finish_ret( (mbedcrypto_ripemd160_context *) ctx,
+ output ) );
+}
+
+static void *ripemd160_ctx_alloc( void )
+{
+ void *ctx = mbedcrypto_calloc( 1, sizeof( mbedcrypto_ripemd160_context ) );
+
+ if( ctx != NULL )
+ mbedcrypto_ripemd160_init( (mbedcrypto_ripemd160_context *) ctx );
+
+ return( ctx );
+}
+
+static void ripemd160_ctx_free( void *ctx )
+{
+ mbedcrypto_ripemd160_free( (mbedcrypto_ripemd160_context *) ctx );
+ mbedcrypto_free( ctx );
+}
+
+static void ripemd160_clone_wrap( void *dst, const void *src )
+{
+ mbedcrypto_ripemd160_clone( (mbedcrypto_ripemd160_context *) dst,
+ (const mbedcrypto_ripemd160_context *) src );
+}
+
+static int ripemd160_process_wrap( void *ctx, const unsigned char *data )
+{
+ return( mbedcrypto_internal_ripemd160_process(
+ (mbedcrypto_ripemd160_context *) ctx, data ) );
+}
+
+const mbedcrypto_md_info_t mbedcrypto_ripemd160_info = {
+ MBEDCRYPTO_MD_RIPEMD160,
+ "RIPEMD160",
+ 20,
+ 64,
+ ripemd160_starts_wrap,
+ ripemd160_update_wrap,
+ ripemd160_finish_wrap,
+ mbedcrypto_ripemd160_ret,
+ ripemd160_ctx_alloc,
+ ripemd160_ctx_free,
+ ripemd160_clone_wrap,
+ ripemd160_process_wrap,
+};
+
+#endif /* MBEDCRYPTO_RIPEMD160_C */
+
+#if defined(MBEDCRYPTO_SHA1_C)
+
+static int sha1_starts_wrap( void *ctx )
+{
+ return( mbedcrypto_sha1_starts_ret( (mbedcrypto_sha1_context *) ctx ) );
+}
+
+static int sha1_update_wrap( void *ctx, const unsigned char *input,
+ size_t ilen )
+{
+ return( mbedcrypto_sha1_update_ret( (mbedcrypto_sha1_context *) ctx,
+ input, ilen ) );
+}
+
+static int sha1_finish_wrap( void *ctx, unsigned char *output )
+{
+ return( mbedcrypto_sha1_finish_ret( (mbedcrypto_sha1_context *) ctx, output ) );
+}
+
+static void *sha1_ctx_alloc( void )
+{
+ void *ctx = mbedcrypto_calloc( 1, sizeof( mbedcrypto_sha1_context ) );
+
+ if( ctx != NULL )
+ mbedcrypto_sha1_init( (mbedcrypto_sha1_context *) ctx );
+
+ return( ctx );
+}
+
+static void sha1_clone_wrap( void *dst, const void *src )
+{
+ mbedcrypto_sha1_clone( (mbedcrypto_sha1_context *) dst,
+ (const mbedcrypto_sha1_context *) src );
+}
+
+static void sha1_ctx_free( void *ctx )
+{
+ mbedcrypto_sha1_free( (mbedcrypto_sha1_context *) ctx );
+ mbedcrypto_free( ctx );
+}
+
+static int sha1_process_wrap( void *ctx, const unsigned char *data )
+{
+ return( mbedcrypto_internal_sha1_process( (mbedcrypto_sha1_context *) ctx,
+ data ) );
+}
+
+const mbedcrypto_md_info_t mbedcrypto_sha1_info = {
+ MBEDCRYPTO_MD_SHA1,
+ "SHA1",
+ 20,
+ 64,
+ sha1_starts_wrap,
+ sha1_update_wrap,
+ sha1_finish_wrap,
+ mbedcrypto_sha1_ret,
+ sha1_ctx_alloc,
+ sha1_ctx_free,
+ sha1_clone_wrap,
+ sha1_process_wrap,
+};
+
+#endif /* MBEDCRYPTO_SHA1_C */
+
+/*
+ * Wrappers for generic message digests
+ */
+#if defined(MBEDCRYPTO_SHA256_C)
+
+static int sha224_starts_wrap( void *ctx )
+{
+ return( mbedcrypto_sha256_starts_ret( (mbedcrypto_sha256_context *) ctx, 1 ) );
+}
+
+static int sha224_update_wrap( void *ctx, const unsigned char *input,
+ size_t ilen )
+{
+ return( mbedcrypto_sha256_update_ret( (mbedcrypto_sha256_context *) ctx,
+ input, ilen ) );
+}
+
+static int sha224_finish_wrap( void *ctx, unsigned char *output )
+{
+ return( mbedcrypto_sha256_finish_ret( (mbedcrypto_sha256_context *) ctx,
+ output ) );
+}
+
+static int sha224_wrap( const unsigned char *input, size_t ilen,
+ unsigned char *output )
+{
+ return( mbedcrypto_sha256_ret( input, ilen, output, 1 ) );
+}
+
+static void *sha224_ctx_alloc( void )
+{
+ void *ctx = mbedcrypto_calloc( 1, sizeof( mbedcrypto_sha256_context ) );
+
+ if( ctx != NULL )
+ mbedcrypto_sha256_init( (mbedcrypto_sha256_context *) ctx );
+
+ return( ctx );
+}
+
+static void sha224_ctx_free( void *ctx )
+{
+ mbedcrypto_sha256_free( (mbedcrypto_sha256_context *) ctx );
+ mbedcrypto_free( ctx );
+}
+
+static void sha224_clone_wrap( void *dst, const void *src )
+{
+ mbedcrypto_sha256_clone( (mbedcrypto_sha256_context *) dst,
+ (const mbedcrypto_sha256_context *) src );
+}
+
+static int sha224_process_wrap( void *ctx, const unsigned char *data )
+{
+ return( mbedcrypto_internal_sha256_process( (mbedcrypto_sha256_context *) ctx,
+ data ) );
+}
+
+const mbedcrypto_md_info_t mbedcrypto_sha224_info = {
+ MBEDCRYPTO_MD_SHA224,
+ "SHA224",
+ 28,
+ 64,
+ sha224_starts_wrap,
+ sha224_update_wrap,
+ sha224_finish_wrap,
+ sha224_wrap,
+ sha224_ctx_alloc,
+ sha224_ctx_free,
+ sha224_clone_wrap,
+ sha224_process_wrap,
+};
+
+static int sha256_starts_wrap( void *ctx )
+{
+ return( mbedcrypto_sha256_starts_ret( (mbedcrypto_sha256_context *) ctx, 0 ) );
+}
+
+static int sha256_wrap( const unsigned char *input, size_t ilen,
+ unsigned char *output )
+{
+ return( mbedcrypto_sha256_ret( input, ilen, output, 0 ) );
+}
+
+const mbedcrypto_md_info_t mbedcrypto_sha256_info = {
+ MBEDCRYPTO_MD_SHA256,
+ "SHA256",
+ 32,
+ 64,
+ sha256_starts_wrap,
+ sha224_update_wrap,
+ sha224_finish_wrap,
+ sha256_wrap,
+ sha224_ctx_alloc,
+ sha224_ctx_free,
+ sha224_clone_wrap,
+ sha224_process_wrap,
+};
+
+#endif /* MBEDCRYPTO_SHA256_C */
+
+#if defined(MBEDCRYPTO_SHA512_C)
+
+static int sha384_starts_wrap( void *ctx )
+{
+ return( mbedcrypto_sha512_starts_ret( (mbedcrypto_sha512_context *) ctx, 1 ) );
+}
+
+static int sha384_update_wrap( void *ctx, const unsigned char *input,
+ size_t ilen )
+{
+ return( mbedcrypto_sha512_update_ret( (mbedcrypto_sha512_context *) ctx,
+ input, ilen ) );
+}
+
+static int sha384_finish_wrap( void *ctx, unsigned char *output )
+{
+ return( mbedcrypto_sha512_finish_ret( (mbedcrypto_sha512_context *) ctx,
+ output ) );
+}
+
+static int sha384_wrap( const unsigned char *input, size_t ilen,
+ unsigned char *output )
+{
+ return( mbedcrypto_sha512_ret( input, ilen, output, 1 ) );
+}
+
+static void *sha384_ctx_alloc( void )
+{
+ void *ctx = mbedcrypto_calloc( 1, sizeof( mbedcrypto_sha512_context ) );
+
+ if( ctx != NULL )
+ mbedcrypto_sha512_init( (mbedcrypto_sha512_context *) ctx );
+
+ return( ctx );
+}
+
+static void sha384_ctx_free( void *ctx )
+{
+ mbedcrypto_sha512_free( (mbedcrypto_sha512_context *) ctx );
+ mbedcrypto_free( ctx );
+}
+
+static void sha384_clone_wrap( void *dst, const void *src )
+{
+ mbedcrypto_sha512_clone( (mbedcrypto_sha512_context *) dst,
+ (const mbedcrypto_sha512_context *) src );
+}
+
+static int sha384_process_wrap( void *ctx, const unsigned char *data )
+{
+ return( mbedcrypto_internal_sha512_process( (mbedcrypto_sha512_context *) ctx,
+ data ) );
+}
+
+const mbedcrypto_md_info_t mbedcrypto_sha384_info = {
+ MBEDCRYPTO_MD_SHA384,
+ "SHA384",
+ 48,
+ 128,
+ sha384_starts_wrap,
+ sha384_update_wrap,
+ sha384_finish_wrap,
+ sha384_wrap,
+ sha384_ctx_alloc,
+ sha384_ctx_free,
+ sha384_clone_wrap,
+ sha384_process_wrap,
+};
+
+static int sha512_starts_wrap( void *ctx )
+{
+ return( mbedcrypto_sha512_starts_ret( (mbedcrypto_sha512_context *) ctx, 0 ) );
+}
+
+static int sha512_wrap( const unsigned char *input, size_t ilen,
+ unsigned char *output )
+{
+ return( mbedcrypto_sha512_ret( input, ilen, output, 0 ) );
+}
+
+const mbedcrypto_md_info_t mbedcrypto_sha512_info = {
+ MBEDCRYPTO_MD_SHA512,
+ "SHA512",
+ 64,
+ 128,
+ sha512_starts_wrap,
+ sha384_update_wrap,
+ sha384_finish_wrap,
+ sha512_wrap,
+ sha384_ctx_alloc,
+ sha384_ctx_free,
+ sha384_clone_wrap,
+ sha384_process_wrap,
+};
+
+#endif /* MBEDCRYPTO_SHA512_C */
+
+#endif /* MBEDCRYPTO_MD_C */
diff --git a/library/oid.c b/library/oid.c
new file mode 100644
index 0000000..000b833
--- /dev/null
+++ b/library/oid.c
@@ -0,0 +1,755 @@
+/**
+ * \file oid.c
+ *
+ * \brief Object Identifier (OID) database
+ *
+ * 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 Crypto (https://tls.mbed.org)
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_OID_C)
+
+#include "mbedcrypto/oid.h"
+#include "mbedcrypto/rsa.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#define mbedcrypto_snprintf snprintf
+#endif
+
+#if defined(MBEDCRYPTO_X509_USE_C) || defined(MBEDCRYPTO_X509_CREATE_C)
+#include "mbedcrypto/x509.h"
+#endif
+
+/*
+ * Macro to automatically add the size of #define'd OIDs
+ */
+#define ADD_LEN(s) s, MBEDCRYPTO_OID_SIZE(s)
+
+/*
+ * Macro to generate an internal function for oid_XXX_from_asn1() (used by
+ * the other functions)
+ */
+#define FN_OID_TYPED_FROM_ASN1( TYPE_T, NAME, LIST ) \
+static const TYPE_T * oid_ ## NAME ## _from_asn1( const mbedcrypto_asn1_buf *oid ) \
+{ \
+ const TYPE_T *p = LIST; \
+ const mbedcrypto_oid_descriptor_t *cur = (const mbedcrypto_oid_descriptor_t *) p; \
+ if( p == NULL || oid == NULL ) return( NULL ); \
+ while( cur->asn1 != NULL ) { \
+ if( cur->asn1_len == oid->len && \
+ memcmp( cur->asn1, oid->p, oid->len ) == 0 ) { \
+ return( p ); \
+ } \
+ p++; \
+ cur = (const mbedcrypto_oid_descriptor_t *) p; \
+ } \
+ return( NULL ); \
+}
+
+/*
+ * Macro to generate a function for retrieving a single attribute from the
+ * descriptor of an mbedcrypto_oid_descriptor_t wrapper.
+ */
+#define FN_OID_GET_DESCRIPTOR_ATTR1(FN_NAME, TYPE_T, TYPE_NAME, ATTR1_TYPE, ATTR1) \
+int FN_NAME( const mbedcrypto_asn1_buf *oid, ATTR1_TYPE * ATTR1 ) \
+{ \
+ const TYPE_T *data = oid_ ## TYPE_NAME ## _from_asn1( oid ); \
+ if( data == NULL ) return( MBEDCRYPTO_ERR_OID_NOT_FOUND ); \
+ *ATTR1 = data->descriptor.ATTR1; \
+ return( 0 ); \
+}
+
+/*
+ * Macro to generate a function for retrieving a single attribute from an
+ * mbedcrypto_oid_descriptor_t wrapper.
+ */
+#define FN_OID_GET_ATTR1(FN_NAME, TYPE_T, TYPE_NAME, ATTR1_TYPE, ATTR1) \
+int FN_NAME( const mbedcrypto_asn1_buf *oid, ATTR1_TYPE * ATTR1 ) \
+{ \
+ const TYPE_T *data = oid_ ## TYPE_NAME ## _from_asn1( oid ); \
+ if( data == NULL ) return( MBEDCRYPTO_ERR_OID_NOT_FOUND ); \
+ *ATTR1 = data->ATTR1; \
+ return( 0 ); \
+}
+
+/*
+ * Macro to generate a function for retrieving two attributes from an
+ * mbedcrypto_oid_descriptor_t wrapper.
+ */
+#define FN_OID_GET_ATTR2(FN_NAME, TYPE_T, TYPE_NAME, ATTR1_TYPE, ATTR1, \
+ ATTR2_TYPE, ATTR2) \
+int FN_NAME( const mbedcrypto_asn1_buf *oid, ATTR1_TYPE * ATTR1, ATTR2_TYPE * ATTR2 ) \
+{ \
+ const TYPE_T *data = oid_ ## TYPE_NAME ## _from_asn1( oid ); \
+ if( data == NULL ) return( MBEDCRYPTO_ERR_OID_NOT_FOUND ); \
+ *ATTR1 = data->ATTR1; \
+ *ATTR2 = data->ATTR2; \
+ return( 0 ); \
+}
+
+/*
+ * Macro to generate a function for retrieving the OID based on a single
+ * attribute from a mbedcrypto_oid_descriptor_t wrapper.
+ */
+#define FN_OID_GET_OID_BY_ATTR1(FN_NAME, TYPE_T, LIST, ATTR1_TYPE, ATTR1) \
+int FN_NAME( ATTR1_TYPE ATTR1, const char **oid, size_t *olen ) \
+{ \
+ const TYPE_T *cur = LIST; \
+ while( cur->descriptor.asn1 != NULL ) { \
+ if( cur->ATTR1 == ATTR1 ) { \
+ *oid = cur->descriptor.asn1; \
+ *olen = cur->descriptor.asn1_len; \
+ return( 0 ); \
+ } \
+ cur++; \
+ } \
+ return( MBEDCRYPTO_ERR_OID_NOT_FOUND ); \
+}
+
+/*
+ * Macro to generate a function for retrieving the OID based on two
+ * attributes from a mbedcrypto_oid_descriptor_t wrapper.
+ */
+#define FN_OID_GET_OID_BY_ATTR2(FN_NAME, TYPE_T, LIST, ATTR1_TYPE, ATTR1, \
+ ATTR2_TYPE, ATTR2) \
+int FN_NAME( ATTR1_TYPE ATTR1, ATTR2_TYPE ATTR2, const char **oid , \
+ size_t *olen ) \
+{ \
+ const TYPE_T *cur = LIST; \
+ while( cur->descriptor.asn1 != NULL ) { \
+ if( cur->ATTR1 == ATTR1 && cur->ATTR2 == ATTR2 ) { \
+ *oid = cur->descriptor.asn1; \
+ *olen = cur->descriptor.asn1_len; \
+ return( 0 ); \
+ } \
+ cur++; \
+ } \
+ return( MBEDCRYPTO_ERR_OID_NOT_FOUND ); \
+}
+
+#if defined(MBEDCRYPTO_X509_USE_C) || defined(MBEDCRYPTO_X509_CREATE_C)
+/*
+ * For X520 attribute types
+ */
+typedef struct {
+ mbedcrypto_oid_descriptor_t descriptor;
+ const char *short_name;
+} oid_x520_attr_t;
+
+static const oid_x520_attr_t oid_x520_attr_type[] =
+{
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_AT_CN ), "id-at-commonName", "Common Name" },
+ "CN",
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_AT_COUNTRY ), "id-at-countryName", "Country" },
+ "C",
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_AT_LOCALITY ), "id-at-locality", "Locality" },
+ "L",
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_AT_STATE ), "id-at-state", "State" },
+ "ST",
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_AT_ORGANIZATION ),"id-at-organizationName", "Organization" },
+ "O",
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_AT_ORG_UNIT ), "id-at-organizationalUnitName", "Org Unit" },
+ "OU",
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_PKCS9_EMAIL ), "emailAddress", "E-mail address" },
+ "emailAddress",
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_AT_SERIAL_NUMBER ),"id-at-serialNumber", "Serial number" },
+ "serialNumber",
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_AT_POSTAL_ADDRESS ),"id-at-postalAddress", "Postal address" },
+ "postalAddress",
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_AT_POSTAL_CODE ), "id-at-postalCode", "Postal code" },
+ "postalCode",
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_AT_SUR_NAME ), "id-at-surName", "Surname" },
+ "SN",
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_AT_GIVEN_NAME ), "id-at-givenName", "Given name" },
+ "GN",
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_AT_INITIALS ), "id-at-initials", "Initials" },
+ "initials",
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_AT_GENERATION_QUALIFIER ), "id-at-generationQualifier", "Generation qualifier" },
+ "generationQualifier",
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_AT_TITLE ), "id-at-title", "Title" },
+ "title",
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_AT_DN_QUALIFIER ),"id-at-dnQualifier", "Distinguished Name qualifier" },
+ "dnQualifier",
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_AT_PSEUDONYM ), "id-at-pseudonym", "Pseudonym" },
+ "pseudonym",
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_DOMAIN_COMPONENT ), "id-domainComponent", "Domain component" },
+ "DC",
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_AT_UNIQUE_IDENTIFIER ), "id-at-uniqueIdentifier", "Unique Identifier" },
+ "uniqueIdentifier",
+ },
+ {
+ { NULL, 0, NULL, NULL },
+ NULL,
+ }
+};
+
+FN_OID_TYPED_FROM_ASN1(oid_x520_attr_t, x520_attr, oid_x520_attr_type)
+FN_OID_GET_ATTR1(mbedcrypto_oid_get_attr_short_name, oid_x520_attr_t, x520_attr, const char *, short_name)
+
+/*
+ * For X509 extensions
+ */
+typedef struct {
+ mbedcrypto_oid_descriptor_t descriptor;
+ int ext_type;
+} oid_x509_ext_t;
+
+static const oid_x509_ext_t oid_x509_ext[] =
+{
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_BASIC_CONSTRAINTS ), "id-ce-basicConstraints", "Basic Constraints" },
+ MBEDCRYPTO_X509_EXT_BASIC_CONSTRAINTS,
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_KEY_USAGE ), "id-ce-keyUsage", "Key Usage" },
+ MBEDCRYPTO_X509_EXT_KEY_USAGE,
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_EXTENDED_KEY_USAGE ), "id-ce-extKeyUsage", "Extended Key Usage" },
+ MBEDCRYPTO_X509_EXT_EXTENDED_KEY_USAGE,
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_SUBJECT_ALT_NAME ), "id-ce-subjectAltName", "Subject Alt Name" },
+ MBEDCRYPTO_X509_EXT_SUBJECT_ALT_NAME,
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_NS_CERT_TYPE ), "id-netscape-certtype", "Netscape Certificate Type" },
+ MBEDCRYPTO_X509_EXT_NS_CERT_TYPE,
+ },
+ {
+ { NULL, 0, NULL, NULL },
+ 0,
+ },
+};
+
+FN_OID_TYPED_FROM_ASN1(oid_x509_ext_t, x509_ext, oid_x509_ext)
+FN_OID_GET_ATTR1(mbedcrypto_oid_get_x509_ext_type, oid_x509_ext_t, x509_ext, int, ext_type)
+
+static const mbedcrypto_oid_descriptor_t oid_ext_key_usage[] =
+{
+ { ADD_LEN( MBEDCRYPTO_OID_SERVER_AUTH ), "id-kp-serverAuth", "TLS Web Server Authentication" },
+ { ADD_LEN( MBEDCRYPTO_OID_CLIENT_AUTH ), "id-kp-clientAuth", "TLS Web Client Authentication" },
+ { ADD_LEN( MBEDCRYPTO_OID_CODE_SIGNING ), "id-kp-codeSigning", "Code Signing" },
+ { ADD_LEN( MBEDCRYPTO_OID_EMAIL_PROTECTION ), "id-kp-emailProtection", "E-mail Protection" },
+ { ADD_LEN( MBEDCRYPTO_OID_TIME_STAMPING ), "id-kp-timeStamping", "Time Stamping" },
+ { ADD_LEN( MBEDCRYPTO_OID_OCSP_SIGNING ), "id-kp-OCSPSigning", "OCSP Signing" },
+ { NULL, 0, NULL, NULL },
+};
+
+FN_OID_TYPED_FROM_ASN1(mbedcrypto_oid_descriptor_t, ext_key_usage, oid_ext_key_usage)
+FN_OID_GET_ATTR1(mbedcrypto_oid_get_extended_key_usage, mbedcrypto_oid_descriptor_t, ext_key_usage, const char *, description)
+#endif /* MBEDCRYPTO_X509_USE_C || MBEDCRYPTO_X509_CREATE_C */
+
+#if defined(MBEDCRYPTO_MD_C)
+/*
+ * For SignatureAlgorithmIdentifier
+ */
+typedef struct {
+ mbedcrypto_oid_descriptor_t descriptor;
+ mbedcrypto_md_type_t md_alg;
+ mbedcrypto_pk_type_t pk_alg;
+} oid_sig_alg_t;
+
+static const oid_sig_alg_t oid_sig_alg[] =
+{
+#if defined(MBEDCRYPTO_RSA_C)
+#if defined(MBEDCRYPTO_MD2_C)
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_PKCS1_MD2 ), "md2WithRSAEncryption", "RSA with MD2" },
+ MBEDCRYPTO_MD_MD2, MBEDCRYPTO_PK_RSA,
+ },
+#endif /* MBEDCRYPTO_MD2_C */
+#if defined(MBEDCRYPTO_MD4_C)
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_PKCS1_MD4 ), "md4WithRSAEncryption", "RSA with MD4" },
+ MBEDCRYPTO_MD_MD4, MBEDCRYPTO_PK_RSA,
+ },
+#endif /* MBEDCRYPTO_MD4_C */
+#if defined(MBEDCRYPTO_MD5_C)
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_PKCS1_MD5 ), "md5WithRSAEncryption", "RSA with MD5" },
+ MBEDCRYPTO_MD_MD5, MBEDCRYPTO_PK_RSA,
+ },
+#endif /* MBEDCRYPTO_MD5_C */
+#if defined(MBEDCRYPTO_SHA1_C)
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_PKCS1_SHA1 ), "sha-1WithRSAEncryption", "RSA with SHA1" },
+ MBEDCRYPTO_MD_SHA1, MBEDCRYPTO_PK_RSA,
+ },
+#endif /* MBEDCRYPTO_SHA1_C */
+#if defined(MBEDCRYPTO_SHA256_C)
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_PKCS1_SHA224 ), "sha224WithRSAEncryption", "RSA with SHA-224" },
+ MBEDCRYPTO_MD_SHA224, MBEDCRYPTO_PK_RSA,
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_PKCS1_SHA256 ), "sha256WithRSAEncryption", "RSA with SHA-256" },
+ MBEDCRYPTO_MD_SHA256, MBEDCRYPTO_PK_RSA,
+ },
+#endif /* MBEDCRYPTO_SHA256_C */
+#if defined(MBEDCRYPTO_SHA512_C)
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_PKCS1_SHA384 ), "sha384WithRSAEncryption", "RSA with SHA-384" },
+ MBEDCRYPTO_MD_SHA384, MBEDCRYPTO_PK_RSA,
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_PKCS1_SHA512 ), "sha512WithRSAEncryption", "RSA with SHA-512" },
+ MBEDCRYPTO_MD_SHA512, MBEDCRYPTO_PK_RSA,
+ },
+#endif /* MBEDCRYPTO_SHA512_C */
+#if defined(MBEDCRYPTO_SHA1_C)
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_RSA_SHA_OBS ), "sha-1WithRSAEncryption", "RSA with SHA1" },
+ MBEDCRYPTO_MD_SHA1, MBEDCRYPTO_PK_RSA,
+ },
+#endif /* MBEDCRYPTO_SHA1_C */
+#endif /* MBEDCRYPTO_RSA_C */
+#if defined(MBEDCRYPTO_ECDSA_C)
+#if defined(MBEDCRYPTO_SHA1_C)
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_ECDSA_SHA1 ), "ecdsa-with-SHA1", "ECDSA with SHA1" },
+ MBEDCRYPTO_MD_SHA1, MBEDCRYPTO_PK_ECDSA,
+ },
+#endif /* MBEDCRYPTO_SHA1_C */
+#if defined(MBEDCRYPTO_SHA256_C)
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_ECDSA_SHA224 ), "ecdsa-with-SHA224", "ECDSA with SHA224" },
+ MBEDCRYPTO_MD_SHA224, MBEDCRYPTO_PK_ECDSA,
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_ECDSA_SHA256 ), "ecdsa-with-SHA256", "ECDSA with SHA256" },
+ MBEDCRYPTO_MD_SHA256, MBEDCRYPTO_PK_ECDSA,
+ },
+#endif /* MBEDCRYPTO_SHA256_C */
+#if defined(MBEDCRYPTO_SHA512_C)
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_ECDSA_SHA384 ), "ecdsa-with-SHA384", "ECDSA with SHA384" },
+ MBEDCRYPTO_MD_SHA384, MBEDCRYPTO_PK_ECDSA,
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_ECDSA_SHA512 ), "ecdsa-with-SHA512", "ECDSA with SHA512" },
+ MBEDCRYPTO_MD_SHA512, MBEDCRYPTO_PK_ECDSA,
+ },
+#endif /* MBEDCRYPTO_SHA512_C */
+#endif /* MBEDCRYPTO_ECDSA_C */
+#if defined(MBEDCRYPTO_RSA_C)
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_RSASSA_PSS ), "RSASSA-PSS", "RSASSA-PSS" },
+ MBEDCRYPTO_MD_NONE, MBEDCRYPTO_PK_RSASSA_PSS,
+ },
+#endif /* MBEDCRYPTO_RSA_C */
+ {
+ { NULL, 0, NULL, NULL },
+ MBEDCRYPTO_MD_NONE, MBEDCRYPTO_PK_NONE,
+ },
+};
+
+FN_OID_TYPED_FROM_ASN1(oid_sig_alg_t, sig_alg, oid_sig_alg)
+FN_OID_GET_DESCRIPTOR_ATTR1(mbedcrypto_oid_get_sig_alg_desc, oid_sig_alg_t, sig_alg, const char *, description)
+FN_OID_GET_ATTR2(mbedcrypto_oid_get_sig_alg, oid_sig_alg_t, sig_alg, mbedcrypto_md_type_t, md_alg, mbedcrypto_pk_type_t, pk_alg)
+FN_OID_GET_OID_BY_ATTR2(mbedcrypto_oid_get_oid_by_sig_alg, oid_sig_alg_t, oid_sig_alg, mbedcrypto_pk_type_t, pk_alg, mbedcrypto_md_type_t, md_alg)
+#endif /* MBEDCRYPTO_MD_C */
+
+/*
+ * For PublicKeyInfo (PKCS1, RFC 5480)
+ */
+typedef struct {
+ mbedcrypto_oid_descriptor_t descriptor;
+ mbedcrypto_pk_type_t pk_alg;
+} oid_pk_alg_t;
+
+static const oid_pk_alg_t oid_pk_alg[] =
+{
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_PKCS1_RSA ), "rsaEncryption", "RSA" },
+ MBEDCRYPTO_PK_RSA,
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_EC_ALG_UNRESTRICTED ), "id-ecPublicKey", "Generic EC key" },
+ MBEDCRYPTO_PK_ECKEY,
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_EC_ALG_ECDH ), "id-ecDH", "EC key for ECDH" },
+ MBEDCRYPTO_PK_ECKEY_DH,
+ },
+ {
+ { NULL, 0, NULL, NULL },
+ MBEDCRYPTO_PK_NONE,
+ },
+};
+
+FN_OID_TYPED_FROM_ASN1(oid_pk_alg_t, pk_alg, oid_pk_alg)
+FN_OID_GET_ATTR1(mbedcrypto_oid_get_pk_alg, oid_pk_alg_t, pk_alg, mbedcrypto_pk_type_t, pk_alg)
+FN_OID_GET_OID_BY_ATTR1(mbedcrypto_oid_get_oid_by_pk_alg, oid_pk_alg_t, oid_pk_alg, mbedcrypto_pk_type_t, pk_alg)
+
+#if defined(MBEDCRYPTO_ECP_C)
+/*
+ * For namedCurve (RFC 5480)
+ */
+typedef struct {
+ mbedcrypto_oid_descriptor_t descriptor;
+ mbedcrypto_ecp_group_id grp_id;
+} oid_ecp_grp_t;
+
+static const oid_ecp_grp_t oid_ecp_grp[] =
+{
+#if defined(MBEDCRYPTO_ECP_DP_SECP192R1_ENABLED)
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_EC_GRP_SECP192R1 ), "secp192r1", "secp192r1" },
+ MBEDCRYPTO_ECP_DP_SECP192R1,
+ },
+#endif /* MBEDCRYPTO_ECP_DP_SECP192R1_ENABLED */
+#if defined(MBEDCRYPTO_ECP_DP_SECP224R1_ENABLED)
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_EC_GRP_SECP224R1 ), "secp224r1", "secp224r1" },
+ MBEDCRYPTO_ECP_DP_SECP224R1,
+ },
+#endif /* MBEDCRYPTO_ECP_DP_SECP224R1_ENABLED */
+#if defined(MBEDCRYPTO_ECP_DP_SECP256R1_ENABLED)
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_EC_GRP_SECP256R1 ), "secp256r1", "secp256r1" },
+ MBEDCRYPTO_ECP_DP_SECP256R1,
+ },
+#endif /* MBEDCRYPTO_ECP_DP_SECP256R1_ENABLED */
+#if defined(MBEDCRYPTO_ECP_DP_SECP384R1_ENABLED)
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_EC_GRP_SECP384R1 ), "secp384r1", "secp384r1" },
+ MBEDCRYPTO_ECP_DP_SECP384R1,
+ },
+#endif /* MBEDCRYPTO_ECP_DP_SECP384R1_ENABLED */
+#if defined(MBEDCRYPTO_ECP_DP_SECP521R1_ENABLED)
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_EC_GRP_SECP521R1 ), "secp521r1", "secp521r1" },
+ MBEDCRYPTO_ECP_DP_SECP521R1,
+ },
+#endif /* MBEDCRYPTO_ECP_DP_SECP521R1_ENABLED */
+#if defined(MBEDCRYPTO_ECP_DP_SECP192K1_ENABLED)
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_EC_GRP_SECP192K1 ), "secp192k1", "secp192k1" },
+ MBEDCRYPTO_ECP_DP_SECP192K1,
+ },
+#endif /* MBEDCRYPTO_ECP_DP_SECP192K1_ENABLED */
+#if defined(MBEDCRYPTO_ECP_DP_SECP224K1_ENABLED)
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_EC_GRP_SECP224K1 ), "secp224k1", "secp224k1" },
+ MBEDCRYPTO_ECP_DP_SECP224K1,
+ },
+#endif /* MBEDCRYPTO_ECP_DP_SECP224K1_ENABLED */
+#if defined(MBEDCRYPTO_ECP_DP_SECP256K1_ENABLED)
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_EC_GRP_SECP256K1 ), "secp256k1", "secp256k1" },
+ MBEDCRYPTO_ECP_DP_SECP256K1,
+ },
+#endif /* MBEDCRYPTO_ECP_DP_SECP256K1_ENABLED */
+#if defined(MBEDCRYPTO_ECP_DP_BP256R1_ENABLED)
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_EC_GRP_BP256R1 ), "brainpoolP256r1","brainpool256r1" },
+ MBEDCRYPTO_ECP_DP_BP256R1,
+ },
+#endif /* MBEDCRYPTO_ECP_DP_BP256R1_ENABLED */
+#if defined(MBEDCRYPTO_ECP_DP_BP384R1_ENABLED)
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_EC_GRP_BP384R1 ), "brainpoolP384r1","brainpool384r1" },
+ MBEDCRYPTO_ECP_DP_BP384R1,
+ },
+#endif /* MBEDCRYPTO_ECP_DP_BP384R1_ENABLED */
+#if defined(MBEDCRYPTO_ECP_DP_BP512R1_ENABLED)
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_EC_GRP_BP512R1 ), "brainpoolP512r1","brainpool512r1" },
+ MBEDCRYPTO_ECP_DP_BP512R1,
+ },
+#endif /* MBEDCRYPTO_ECP_DP_BP512R1_ENABLED */
+ {
+ { NULL, 0, NULL, NULL },
+ MBEDCRYPTO_ECP_DP_NONE,
+ },
+};
+
+FN_OID_TYPED_FROM_ASN1(oid_ecp_grp_t, grp_id, oid_ecp_grp)
+FN_OID_GET_ATTR1(mbedcrypto_oid_get_ec_grp, oid_ecp_grp_t, grp_id, mbedcrypto_ecp_group_id, grp_id)
+FN_OID_GET_OID_BY_ATTR1(mbedcrypto_oid_get_oid_by_ec_grp, oid_ecp_grp_t, oid_ecp_grp, mbedcrypto_ecp_group_id, grp_id)
+#endif /* MBEDCRYPTO_ECP_C */
+
+#if defined(MBEDCRYPTO_CIPHER_C)
+/*
+ * For PKCS#5 PBES2 encryption algorithm
+ */
+typedef struct {
+ mbedcrypto_oid_descriptor_t descriptor;
+ mbedcrypto_cipher_type_t cipher_alg;
+} oid_cipher_alg_t;
+
+static const oid_cipher_alg_t oid_cipher_alg[] =
+{
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_DES_CBC ), "desCBC", "DES-CBC" },
+ MBEDCRYPTO_CIPHER_DES_CBC,
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_DES_EDE3_CBC ), "des-ede3-cbc", "DES-EDE3-CBC" },
+ MBEDCRYPTO_CIPHER_DES_EDE3_CBC,
+ },
+ {
+ { NULL, 0, NULL, NULL },
+ MBEDCRYPTO_CIPHER_NONE,
+ },
+};
+
+FN_OID_TYPED_FROM_ASN1(oid_cipher_alg_t, cipher_alg, oid_cipher_alg)
+FN_OID_GET_ATTR1(mbedcrypto_oid_get_cipher_alg, oid_cipher_alg_t, cipher_alg, mbedcrypto_cipher_type_t, cipher_alg)
+#endif /* MBEDCRYPTO_CIPHER_C */
+
+#if defined(MBEDCRYPTO_MD_C)
+/*
+ * For digestAlgorithm
+ */
+typedef struct {
+ mbedcrypto_oid_descriptor_t descriptor;
+ mbedcrypto_md_type_t md_alg;
+} oid_md_alg_t;
+
+static const oid_md_alg_t oid_md_alg[] =
+{
+#if defined(MBEDCRYPTO_MD2_C)
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_DIGEST_ALG_MD2 ), "id-md2", "MD2" },
+ MBEDCRYPTO_MD_MD2,
+ },
+#endif /* MBEDCRYPTO_MD2_C */
+#if defined(MBEDCRYPTO_MD4_C)
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_DIGEST_ALG_MD4 ), "id-md4", "MD4" },
+ MBEDCRYPTO_MD_MD4,
+ },
+#endif /* MBEDCRYPTO_MD4_C */
+#if defined(MBEDCRYPTO_MD5_C)
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_DIGEST_ALG_MD5 ), "id-md5", "MD5" },
+ MBEDCRYPTO_MD_MD5,
+ },
+#endif /* MBEDCRYPTO_MD5_C */
+#if defined(MBEDCRYPTO_SHA1_C)
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_DIGEST_ALG_SHA1 ), "id-sha1", "SHA-1" },
+ MBEDCRYPTO_MD_SHA1,
+ },
+#endif /* MBEDCRYPTO_SHA1_C */
+#if defined(MBEDCRYPTO_SHA256_C)
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_DIGEST_ALG_SHA224 ), "id-sha224", "SHA-224" },
+ MBEDCRYPTO_MD_SHA224,
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_DIGEST_ALG_SHA256 ), "id-sha256", "SHA-256" },
+ MBEDCRYPTO_MD_SHA256,
+ },
+#endif /* MBEDCRYPTO_SHA256_C */
+#if defined(MBEDCRYPTO_SHA512_C)
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_DIGEST_ALG_SHA384 ), "id-sha384", "SHA-384" },
+ MBEDCRYPTO_MD_SHA384,
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_DIGEST_ALG_SHA512 ), "id-sha512", "SHA-512" },
+ MBEDCRYPTO_MD_SHA512,
+ },
+#endif /* MBEDCRYPTO_SHA512_C */
+ {
+ { NULL, 0, NULL, NULL },
+ MBEDCRYPTO_MD_NONE,
+ },
+};
+
+FN_OID_TYPED_FROM_ASN1(oid_md_alg_t, md_alg, oid_md_alg)
+FN_OID_GET_ATTR1(mbedcrypto_oid_get_md_alg, oid_md_alg_t, md_alg, mbedcrypto_md_type_t, md_alg)
+FN_OID_GET_OID_BY_ATTR1(mbedcrypto_oid_get_oid_by_md, oid_md_alg_t, oid_md_alg, mbedcrypto_md_type_t, md_alg)
+
+/*
+ * For HMAC digestAlgorithm
+ */
+typedef struct {
+ mbedcrypto_oid_descriptor_t descriptor;
+ mbedcrypto_md_type_t md_hmac;
+} oid_md_hmac_t;
+
+static const oid_md_hmac_t oid_md_hmac[] =
+{
+#if defined(MBEDCRYPTO_SHA1_C)
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_HMAC_SHA1 ), "hmacSHA1", "HMAC-SHA-1" },
+ MBEDCRYPTO_MD_SHA1,
+ },
+#endif /* MBEDCRYPTO_SHA1_C */
+#if defined(MBEDCRYPTO_SHA256_C)
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_HMAC_SHA224 ), "hmacSHA224", "HMAC-SHA-224" },
+ MBEDCRYPTO_MD_SHA224,
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_HMAC_SHA256 ), "hmacSHA256", "HMAC-SHA-256" },
+ MBEDCRYPTO_MD_SHA256,
+ },
+#endif /* MBEDCRYPTO_SHA256_C */
+#if defined(MBEDCRYPTO_SHA512_C)
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_HMAC_SHA384 ), "hmacSHA384", "HMAC-SHA-384" },
+ MBEDCRYPTO_MD_SHA384,
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_HMAC_SHA512 ), "hmacSHA512", "HMAC-SHA-512" },
+ MBEDCRYPTO_MD_SHA512,
+ },
+#endif /* MBEDCRYPTO_SHA512_C */
+ {
+ { NULL, 0, NULL, NULL },
+ MBEDCRYPTO_MD_NONE,
+ },
+};
+
+FN_OID_TYPED_FROM_ASN1(oid_md_hmac_t, md_hmac, oid_md_hmac)
+FN_OID_GET_ATTR1(mbedcrypto_oid_get_md_hmac, oid_md_hmac_t, md_hmac, mbedcrypto_md_type_t, md_hmac)
+#endif /* MBEDCRYPTO_MD_C */
+
+#if defined(MBEDCRYPTO_PKCS12_C)
+/*
+ * For PKCS#12 PBEs
+ */
+typedef struct {
+ mbedcrypto_oid_descriptor_t descriptor;
+ mbedcrypto_md_type_t md_alg;
+ mbedcrypto_cipher_type_t cipher_alg;
+} oid_pkcs12_pbe_alg_t;
+
+static const oid_pkcs12_pbe_alg_t oid_pkcs12_pbe_alg[] =
+{
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_PKCS12_PBE_SHA1_DES3_EDE_CBC ), "pbeWithSHAAnd3-KeyTripleDES-CBC", "PBE with SHA1 and 3-Key 3DES" },
+ MBEDCRYPTO_MD_SHA1, MBEDCRYPTO_CIPHER_DES_EDE3_CBC,
+ },
+ {
+ { ADD_LEN( MBEDCRYPTO_OID_PKCS12_PBE_SHA1_DES2_EDE_CBC ), "pbeWithSHAAnd2-KeyTripleDES-CBC", "PBE with SHA1 and 2-Key 3DES" },
+ MBEDCRYPTO_MD_SHA1, MBEDCRYPTO_CIPHER_DES_EDE_CBC,
+ },
+ {
+ { NULL, 0, NULL, NULL },
+ MBEDCRYPTO_MD_NONE, MBEDCRYPTO_CIPHER_NONE,
+ },
+};
+
+FN_OID_TYPED_FROM_ASN1(oid_pkcs12_pbe_alg_t, pkcs12_pbe_alg, oid_pkcs12_pbe_alg)
+FN_OID_GET_ATTR2(mbedcrypto_oid_get_pkcs12_pbe_alg, oid_pkcs12_pbe_alg_t, pkcs12_pbe_alg, mbedcrypto_md_type_t, md_alg, mbedcrypto_cipher_type_t, cipher_alg)
+#endif /* MBEDCRYPTO_PKCS12_C */
+
+#define OID_SAFE_SNPRINTF \
+ do { \
+ if( ret < 0 || (size_t) ret >= n ) \
+ return( MBEDCRYPTO_ERR_OID_BUF_TOO_SMALL ); \
+ \
+ n -= (size_t) ret; \
+ p += (size_t) ret; \
+ } while( 0 )
+
+/* Return the x.y.z.... style numeric string for the given OID */
+int mbedcrypto_oid_get_numeric_string( char *buf, size_t size,
+ const mbedcrypto_asn1_buf *oid )
+{
+ int ret;
+ size_t i, n;
+ unsigned int value;
+ char *p;
+
+ p = buf;
+ n = size;
+
+ /* First byte contains first two dots */
+ if( oid->len > 0 )
+ {
+ ret = mbedcrypto_snprintf( p, n, "%d.%d", oid->p[0] / 40, oid->p[0] % 40 );
+ OID_SAFE_SNPRINTF;
+ }
+
+ value = 0;
+ for( i = 1; i < oid->len; i++ )
+ {
+ /* Prevent overflow in value. */
+ if( ( ( value << 7 ) >> 7 ) != value )
+ return( MBEDCRYPTO_ERR_OID_BUF_TOO_SMALL );
+
+ value <<= 7;
+ value += oid->p[i] & 0x7F;
+
+ if( !( oid->p[i] & 0x80 ) )
+ {
+ /* Last byte */
+ ret = mbedcrypto_snprintf( p, n, ".%d", value );
+ OID_SAFE_SNPRINTF;
+ value = 0;
+ }
+ }
+
+ return( (int) ( size - n ) );
+}
+
+#endif /* MBEDCRYPTO_OID_C */
diff --git a/library/pem.c b/library/pem.c
new file mode 100644
index 0000000..a1a9a84
--- /dev/null
+++ b/library/pem.c
@@ -0,0 +1,488 @@
+/*
+ * Privacy Enhanced Mail (PEM) 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 Crypto (https://tls.mbed.org)
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_PEM_PARSE_C) || defined(MBEDCRYPTO_PEM_WRITE_C)
+
+#include "mbedcrypto/pem.h"
+#include "mbedcrypto/base64.h"
+#include "mbedcrypto/des.h"
+#include "mbedcrypto/aes.h"
+#include "mbedcrypto/md5.h"
+#include "mbedcrypto/cipher.h"
+#include "mbedcrypto/platform_util.h"
+
+#include <string.h>
+
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#include <stdlib.h>
+#define mbedcrypto_calloc calloc
+#define mbedcrypto_free free
+#endif
+
+#if defined(MBEDCRYPTO_PEM_PARSE_C)
+void mbedcrypto_pem_init( mbedcrypto_pem_context *ctx )
+{
+ memset( ctx, 0, sizeof( mbedcrypto_pem_context ) );
+}
+
+#if defined(MBEDCRYPTO_MD5_C) && defined(MBEDCRYPTO_CIPHER_MODE_CBC) && \
+ ( defined(MBEDCRYPTO_DES_C) || defined(MBEDCRYPTO_AES_C) )
+/*
+ * Read a 16-byte hex string and convert it to binary
+ */
+static int pem_get_iv( const unsigned char *s, unsigned char *iv,
+ size_t iv_len )
+{
+ size_t i, j, k;
+
+ memset( iv, 0, iv_len );
+
+ for( i = 0; i < iv_len * 2; i++, s++ )
+ {
+ if( *s >= '0' && *s <= '9' ) j = *s - '0'; else
+ if( *s >= 'A' && *s <= 'F' ) j = *s - '7'; else
+ if( *s >= 'a' && *s <= 'f' ) j = *s - 'W'; else
+ return( MBEDCRYPTO_ERR_PEM_INVALID_ENC_IV );
+
+ k = ( ( i & 1 ) != 0 ) ? j : j << 4;
+
+ iv[i >> 1] = (unsigned char)( iv[i >> 1] | k );
+ }
+
+ return( 0 );
+}
+
+static int pem_pbkdf1( unsigned char *key, size_t keylen,
+ unsigned char *iv,
+ const unsigned char *pwd, size_t pwdlen )
+{
+ mbedcrypto_md5_context md5_ctx;
+ unsigned char md5sum[16];
+ size_t use_len;
+ int ret;
+
+ mbedcrypto_md5_init( &md5_ctx );
+
+ /*
+ * key[ 0..15] = MD5(pwd || IV)
+ */
+ if( ( ret = mbedcrypto_md5_starts_ret( &md5_ctx ) ) != 0 )
+ goto exit;
+ if( ( ret = mbedcrypto_md5_update_ret( &md5_ctx, pwd, pwdlen ) ) != 0 )
+ goto exit;
+ if( ( ret = mbedcrypto_md5_update_ret( &md5_ctx, iv, 8 ) ) != 0 )
+ goto exit;
+ if( ( ret = mbedcrypto_md5_finish_ret( &md5_ctx, md5sum ) ) != 0 )
+ goto exit;
+
+ if( keylen <= 16 )
+ {
+ memcpy( key, md5sum, keylen );
+ goto exit;
+ }
+
+ memcpy( key, md5sum, 16 );
+
+ /*
+ * key[16..23] = MD5(key[ 0..15] || pwd || IV])
+ */
+ if( ( ret = mbedcrypto_md5_starts_ret( &md5_ctx ) ) != 0 )
+ goto exit;
+ if( ( ret = mbedcrypto_md5_update_ret( &md5_ctx, md5sum, 16 ) ) != 0 )
+ goto exit;
+ if( ( ret = mbedcrypto_md5_update_ret( &md5_ctx, pwd, pwdlen ) ) != 0 )
+ goto exit;
+ if( ( ret = mbedcrypto_md5_update_ret( &md5_ctx, iv, 8 ) ) != 0 )
+ goto exit;
+ if( ( ret = mbedcrypto_md5_finish_ret( &md5_ctx, md5sum ) ) != 0 )
+ goto exit;
+
+ use_len = 16;
+ if( keylen < 32 )
+ use_len = keylen - 16;
+
+ memcpy( key + 16, md5sum, use_len );
+
+exit:
+ mbedcrypto_md5_free( &md5_ctx );
+ mbedcrypto_platform_zeroize( md5sum, 16 );
+
+ return( ret );
+}
+
+#if defined(MBEDCRYPTO_DES_C)
+/*
+ * Decrypt with DES-CBC, using PBKDF1 for key derivation
+ */
+static int pem_des_decrypt( unsigned char des_iv[8],
+ unsigned char *buf, size_t buflen,
+ const unsigned char *pwd, size_t pwdlen )
+{
+ mbedcrypto_des_context des_ctx;
+ unsigned char des_key[8];
+ int ret;
+
+ mbedcrypto_des_init( &des_ctx );
+
+ if( ( ret = pem_pbkdf1( des_key, 8, des_iv, pwd, pwdlen ) ) != 0 )
+ goto exit;
+
+ if( ( ret = mbedcrypto_des_setkey_dec( &des_ctx, des_key ) ) != 0 )
+ goto exit;
+ ret = mbedcrypto_des_crypt_cbc( &des_ctx, MBEDCRYPTO_DES_DECRYPT, buflen,
+ des_iv, buf, buf );
+
+exit:
+ mbedcrypto_des_free( &des_ctx );
+ mbedcrypto_platform_zeroize( des_key, 8 );
+
+ return( ret );
+}
+
+/*
+ * Decrypt with 3DES-CBC, using PBKDF1 for key derivation
+ */
+static int pem_des3_decrypt( unsigned char des3_iv[8],
+ unsigned char *buf, size_t buflen,
+ const unsigned char *pwd, size_t pwdlen )
+{
+ mbedcrypto_des3_context des3_ctx;
+ unsigned char des3_key[24];
+ int ret;
+
+ mbedcrypto_des3_init( &des3_ctx );
+
+ if( ( ret = pem_pbkdf1( des3_key, 24, des3_iv, pwd, pwdlen ) ) != 0 )
+ goto exit;
+
+ if( ( ret = mbedcrypto_des3_set3key_dec( &des3_ctx, des3_key ) ) != 0 )
+ goto exit;
+ ret = mbedcrypto_des3_crypt_cbc( &des3_ctx, MBEDCRYPTO_DES_DECRYPT, buflen,
+ des3_iv, buf, buf );
+
+exit:
+ mbedcrypto_des3_free( &des3_ctx );
+ mbedcrypto_platform_zeroize( des3_key, 24 );
+
+ return( ret );
+}
+#endif /* MBEDCRYPTO_DES_C */
+
+#if defined(MBEDCRYPTO_AES_C)
+/*
+ * Decrypt with AES-XXX-CBC, using PBKDF1 for key derivation
+ */
+static int pem_aes_decrypt( unsigned char aes_iv[16], unsigned int keylen,
+ unsigned char *buf, size_t buflen,
+ const unsigned char *pwd, size_t pwdlen )
+{
+ mbedcrypto_aes_context aes_ctx;
+ unsigned char aes_key[32];
+ int ret;
+
+ mbedcrypto_aes_init( &aes_ctx );
+
+ if( ( ret = pem_pbkdf1( aes_key, keylen, aes_iv, pwd, pwdlen ) ) != 0 )
+ goto exit;
+
+ if( ( ret = mbedcrypto_aes_setkey_dec( &aes_ctx, aes_key, keylen * 8 ) ) != 0 )
+ goto exit;
+ ret = mbedcrypto_aes_crypt_cbc( &aes_ctx, MBEDCRYPTO_AES_DECRYPT, buflen,
+ aes_iv, buf, buf );
+
+exit:
+ mbedcrypto_aes_free( &aes_ctx );
+ mbedcrypto_platform_zeroize( aes_key, keylen );
+
+ return( ret );
+}
+#endif /* MBEDCRYPTO_AES_C */
+
+#endif /* MBEDCRYPTO_MD5_C && MBEDCRYPTO_CIPHER_MODE_CBC &&
+ ( MBEDCRYPTO_AES_C || MBEDCRYPTO_DES_C ) */
+
+int mbedcrypto_pem_read_buffer( mbedcrypto_pem_context *ctx, const char *header, const char *footer,
+ const unsigned char *data, const unsigned char *pwd,
+ size_t pwdlen, size_t *use_len )
+{
+ int ret, enc;
+ size_t len;
+ unsigned char *buf;
+ const unsigned char *s1, *s2, *end;
+#if defined(MBEDCRYPTO_MD5_C) && defined(MBEDCRYPTO_CIPHER_MODE_CBC) && \
+ ( defined(MBEDCRYPTO_DES_C) || defined(MBEDCRYPTO_AES_C) )
+ unsigned char pem_iv[16];
+ mbedcrypto_cipher_type_t enc_alg = MBEDCRYPTO_CIPHER_NONE;
+#else
+ ((void) pwd);
+ ((void) pwdlen);
+#endif /* MBEDCRYPTO_MD5_C && MBEDCRYPTO_CIPHER_MODE_CBC &&
+ ( MBEDCRYPTO_AES_C || MBEDCRYPTO_DES_C ) */
+
+ if( ctx == NULL )
+ return( MBEDCRYPTO_ERR_PEM_BAD_INPUT_DATA );
+
+ s1 = (unsigned char *) strstr( (const char *) data, header );
+
+ if( s1 == NULL )
+ return( MBEDCRYPTO_ERR_PEM_NO_HEADER_FOOTER_PRESENT );
+
+ s2 = (unsigned char *) strstr( (const char *) data, footer );
+
+ if( s2 == NULL || s2 <= s1 )
+ return( MBEDCRYPTO_ERR_PEM_NO_HEADER_FOOTER_PRESENT );
+
+ s1 += strlen( header );
+ if( *s1 == ' ' ) s1++;
+ if( *s1 == '\r' ) s1++;
+ if( *s1 == '\n' ) s1++;
+ else return( MBEDCRYPTO_ERR_PEM_NO_HEADER_FOOTER_PRESENT );
+
+ end = s2;
+ end += strlen( footer );
+ if( *end == ' ' ) end++;
+ if( *end == '\r' ) end++;
+ if( *end == '\n' ) end++;
+ *use_len = end - data;
+
+ enc = 0;
+
+ if( s2 - s1 >= 22 && memcmp( s1, "Proc-Type: 4,ENCRYPTED", 22 ) == 0 )
+ {
+#if defined(MBEDCRYPTO_MD5_C) && defined(MBEDCRYPTO_CIPHER_MODE_CBC) && \
+ ( defined(MBEDCRYPTO_DES_C) || defined(MBEDCRYPTO_AES_C) )
+ enc++;
+
+ s1 += 22;
+ if( *s1 == '\r' ) s1++;
+ if( *s1 == '\n' ) s1++;
+ else return( MBEDCRYPTO_ERR_PEM_INVALID_DATA );
+
+
+#if defined(MBEDCRYPTO_DES_C)
+ if( s2 - s1 >= 23 && memcmp( s1, "DEK-Info: DES-EDE3-CBC,", 23 ) == 0 )
+ {
+ enc_alg = MBEDCRYPTO_CIPHER_DES_EDE3_CBC;
+
+ s1 += 23;
+ if( s2 - s1 < 16 || pem_get_iv( s1, pem_iv, 8 ) != 0 )
+ return( MBEDCRYPTO_ERR_PEM_INVALID_ENC_IV );
+
+ s1 += 16;
+ }
+ else if( s2 - s1 >= 18 && memcmp( s1, "DEK-Info: DES-CBC,", 18 ) == 0 )
+ {
+ enc_alg = MBEDCRYPTO_CIPHER_DES_CBC;
+
+ s1 += 18;
+ if( s2 - s1 < 16 || pem_get_iv( s1, pem_iv, 8) != 0 )
+ return( MBEDCRYPTO_ERR_PEM_INVALID_ENC_IV );
+
+ s1 += 16;
+ }
+#endif /* MBEDCRYPTO_DES_C */
+
+#if defined(MBEDCRYPTO_AES_C)
+ if( s2 - s1 >= 14 && memcmp( s1, "DEK-Info: AES-", 14 ) == 0 )
+ {
+ if( s2 - s1 < 22 )
+ return( MBEDCRYPTO_ERR_PEM_UNKNOWN_ENC_ALG );
+ else if( memcmp( s1, "DEK-Info: AES-128-CBC,", 22 ) == 0 )
+ enc_alg = MBEDCRYPTO_CIPHER_AES_128_CBC;
+ else if( memcmp( s1, "DEK-Info: AES-192-CBC,", 22 ) == 0 )
+ enc_alg = MBEDCRYPTO_CIPHER_AES_192_CBC;
+ else if( memcmp( s1, "DEK-Info: AES-256-CBC,", 22 ) == 0 )
+ enc_alg = MBEDCRYPTO_CIPHER_AES_256_CBC;
+ else
+ return( MBEDCRYPTO_ERR_PEM_UNKNOWN_ENC_ALG );
+
+ s1 += 22;
+ if( s2 - s1 < 32 || pem_get_iv( s1, pem_iv, 16 ) != 0 )
+ return( MBEDCRYPTO_ERR_PEM_INVALID_ENC_IV );
+
+ s1 += 32;
+ }
+#endif /* MBEDCRYPTO_AES_C */
+
+ if( enc_alg == MBEDCRYPTO_CIPHER_NONE )
+ return( MBEDCRYPTO_ERR_PEM_UNKNOWN_ENC_ALG );
+
+ if( *s1 == '\r' ) s1++;
+ if( *s1 == '\n' ) s1++;
+ else return( MBEDCRYPTO_ERR_PEM_INVALID_DATA );
+#else
+ return( MBEDCRYPTO_ERR_PEM_FEATURE_UNAVAILABLE );
+#endif /* MBEDCRYPTO_MD5_C && MBEDCRYPTO_CIPHER_MODE_CBC &&
+ ( MBEDCRYPTO_AES_C || MBEDCRYPTO_DES_C ) */
+ }
+
+ if( s1 >= s2 )
+ return( MBEDCRYPTO_ERR_PEM_INVALID_DATA );
+
+ ret = mbedcrypto_base64_decode( NULL, 0, &len, s1, s2 - s1 );
+
+ if( ret == MBEDCRYPTO_ERR_BASE64_INVALID_CHARACTER )
+ return( MBEDCRYPTO_ERR_PEM_INVALID_DATA + ret );
+
+ if( ( buf = mbedcrypto_calloc( 1, len ) ) == NULL )
+ return( MBEDCRYPTO_ERR_PEM_ALLOC_FAILED );
+
+ if( ( ret = mbedcrypto_base64_decode( buf, len, &len, s1, s2 - s1 ) ) != 0 )
+ {
+ mbedcrypto_platform_zeroize( buf, len );
+ mbedcrypto_free( buf );
+ return( MBEDCRYPTO_ERR_PEM_INVALID_DATA + ret );
+ }
+
+ if( enc != 0 )
+ {
+#if defined(MBEDCRYPTO_MD5_C) && defined(MBEDCRYPTO_CIPHER_MODE_CBC) && \
+ ( defined(MBEDCRYPTO_DES_C) || defined(MBEDCRYPTO_AES_C) )
+ if( pwd == NULL )
+ {
+ mbedcrypto_platform_zeroize( buf, len );
+ mbedcrypto_free( buf );
+ return( MBEDCRYPTO_ERR_PEM_PASSWORD_REQUIRED );
+ }
+
+ ret = 0;
+
+#if defined(MBEDCRYPTO_DES_C)
+ if( enc_alg == MBEDCRYPTO_CIPHER_DES_EDE3_CBC )
+ ret = pem_des3_decrypt( pem_iv, buf, len, pwd, pwdlen );
+ else if( enc_alg == MBEDCRYPTO_CIPHER_DES_CBC )
+ ret = pem_des_decrypt( pem_iv, buf, len, pwd, pwdlen );
+#endif /* MBEDCRYPTO_DES_C */
+
+#if defined(MBEDCRYPTO_AES_C)
+ if( enc_alg == MBEDCRYPTO_CIPHER_AES_128_CBC )
+ ret = pem_aes_decrypt( pem_iv, 16, buf, len, pwd, pwdlen );
+ else if( enc_alg == MBEDCRYPTO_CIPHER_AES_192_CBC )
+ ret = pem_aes_decrypt( pem_iv, 24, buf, len, pwd, pwdlen );
+ else if( enc_alg == MBEDCRYPTO_CIPHER_AES_256_CBC )
+ ret = pem_aes_decrypt( pem_iv, 32, buf, len, pwd, pwdlen );
+#endif /* MBEDCRYPTO_AES_C */
+
+ if( ret != 0 )
+ {
+ mbedcrypto_free( buf );
+ return( ret );
+ }
+
+ /*
+ * The result will be ASN.1 starting with a SEQUENCE tag, with 1 to 3
+ * length bytes (allow 4 to be sure) in all known use cases.
+ *
+ * Use that as a heuristic to try to detect password mismatches.
+ */
+ if( len <= 2 || buf[0] != 0x30 || buf[1] > 0x83 )
+ {
+ mbedcrypto_platform_zeroize( buf, len );
+ mbedcrypto_free( buf );
+ return( MBEDCRYPTO_ERR_PEM_PASSWORD_MISMATCH );
+ }
+#else
+ mbedcrypto_platform_zeroize( buf, len );
+ mbedcrypto_free( buf );
+ return( MBEDCRYPTO_ERR_PEM_FEATURE_UNAVAILABLE );
+#endif /* MBEDCRYPTO_MD5_C && MBEDCRYPTO_CIPHER_MODE_CBC &&
+ ( MBEDCRYPTO_AES_C || MBEDCRYPTO_DES_C ) */
+ }
+
+ ctx->buf = buf;
+ ctx->buflen = len;
+
+ return( 0 );
+}
+
+void mbedcrypto_pem_free( mbedcrypto_pem_context *ctx )
+{
+ if( ctx->buf != NULL )
+ mbedcrypto_platform_zeroize( ctx->buf, ctx->buflen );
+ mbedcrypto_free( ctx->buf );
+ mbedcrypto_free( ctx->info );
+
+ mbedcrypto_platform_zeroize( ctx, sizeof( mbedcrypto_pem_context ) );
+}
+#endif /* MBEDCRYPTO_PEM_PARSE_C */
+
+#if defined(MBEDCRYPTO_PEM_WRITE_C)
+int mbedcrypto_pem_write_buffer( const char *header, const char *footer,
+ const unsigned char *der_data, size_t der_len,
+ unsigned char *buf, size_t buf_len, size_t *olen )
+{
+ int ret;
+ unsigned char *encode_buf = NULL, *c, *p = buf;
+ size_t len = 0, use_len, add_len = 0;
+
+ mbedcrypto_base64_encode( NULL, 0, &use_len, der_data, der_len );
+ add_len = strlen( header ) + strlen( footer ) + ( use_len / 64 ) + 1;
+
+ if( use_len + add_len > buf_len )
+ {
+ *olen = use_len + add_len;
+ return( MBEDCRYPTO_ERR_BASE64_BUFFER_TOO_SMALL );
+ }
+
+ if( use_len != 0 &&
+ ( ( encode_buf = mbedcrypto_calloc( 1, use_len ) ) == NULL ) )
+ return( MBEDCRYPTO_ERR_PEM_ALLOC_FAILED );
+
+ if( ( ret = mbedcrypto_base64_encode( encode_buf, use_len, &use_len, der_data,
+ der_len ) ) != 0 )
+ {
+ mbedcrypto_free( encode_buf );
+ return( ret );
+ }
+
+ memcpy( p, header, strlen( header ) );
+ p += strlen( header );
+ c = encode_buf;
+
+ while( use_len )
+ {
+ len = ( use_len > 64 ) ? 64 : use_len;
+ memcpy( p, c, len );
+ use_len -= len;
+ p += len;
+ c += len;
+ *p++ = '\n';
+ }
+
+ memcpy( p, footer, strlen( footer ) );
+ p += strlen( footer );
+
+ *p++ = '\0';
+ *olen = p - buf;
+
+ mbedcrypto_free( encode_buf );
+ return( 0 );
+}
+#endif /* MBEDCRYPTO_PEM_WRITE_C */
+#endif /* MBEDCRYPTO_PEM_PARSE_C || MBEDCRYPTO_PEM_WRITE_C */
diff --git a/library/pk.c b/library/pk.c
new file mode 100644
index 0000000..364ef38
--- /dev/null
+++ b/library/pk.c
@@ -0,0 +1,379 @@
+/*
+ * Public Key abstraction layer
+ *
+ * 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 Crypto (https://tls.mbed.org)
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_PK_C)
+#include "mbedcrypto/pk.h"
+#include "mbedcrypto/pk_internal.h"
+
+#include "mbedcrypto/platform_util.h"
+
+#if defined(MBEDCRYPTO_RSA_C)
+#include "mbedcrypto/rsa.h"
+#endif
+#if defined(MBEDCRYPTO_ECP_C)
+#include "mbedcrypto/ecp.h"
+#endif
+#if defined(MBEDCRYPTO_ECDSA_C)
+#include "mbedcrypto/ecdsa.h"
+#endif
+
+#include <limits.h>
+#include <stdint.h>
+
+/*
+ * Initialise a mbedcrypto_pk_context
+ */
+void mbedcrypto_pk_init( mbedcrypto_pk_context *ctx )
+{
+ if( ctx == NULL )
+ return;
+
+ ctx->pk_info = NULL;
+ ctx->pk_ctx = NULL;
+}
+
+/*
+ * Free (the components of) a mbedcrypto_pk_context
+ */
+void mbedcrypto_pk_free( mbedcrypto_pk_context *ctx )
+{
+ if( ctx == NULL || ctx->pk_info == NULL )
+ return;
+
+ ctx->pk_info->ctx_free_func( ctx->pk_ctx );
+
+ mbedcrypto_platform_zeroize( ctx, sizeof( mbedcrypto_pk_context ) );
+}
+
+/*
+ * Get pk_info structure from type
+ */
+const mbedcrypto_pk_info_t * mbedcrypto_pk_info_from_type( mbedcrypto_pk_type_t pk_type )
+{
+ switch( pk_type ) {
+#if defined(MBEDCRYPTO_RSA_C)
+ case MBEDCRYPTO_PK_RSA:
+ return( &mbedcrypto_rsa_info );
+#endif
+#if defined(MBEDCRYPTO_ECP_C)
+ case MBEDCRYPTO_PK_ECKEY:
+ return( &mbedcrypto_eckey_info );
+ case MBEDCRYPTO_PK_ECKEY_DH:
+ return( &mbedcrypto_eckeydh_info );
+#endif
+#if defined(MBEDCRYPTO_ECDSA_C)
+ case MBEDCRYPTO_PK_ECDSA:
+ return( &mbedcrypto_ecdsa_info );
+#endif
+ /* MBEDCRYPTO_PK_RSA_ALT omitted on purpose */
+ default:
+ return( NULL );
+ }
+}
+
+/*
+ * Initialise context
+ */
+int mbedcrypto_pk_setup( mbedcrypto_pk_context *ctx, const mbedcrypto_pk_info_t *info )
+{
+ if( ctx == NULL || info == NULL || ctx->pk_info != NULL )
+ return( MBEDCRYPTO_ERR_PK_BAD_INPUT_DATA );
+
+ if( ( ctx->pk_ctx = info->ctx_alloc_func() ) == NULL )
+ return( MBEDCRYPTO_ERR_PK_ALLOC_FAILED );
+
+ ctx->pk_info = info;
+
+ return( 0 );
+}
+
+#if defined(MBEDCRYPTO_PK_RSA_ALT_SUPPORT)
+/*
+ * Initialize an RSA-alt context
+ */
+int mbedcrypto_pk_setup_rsa_alt( mbedcrypto_pk_context *ctx, void * key,
+ mbedcrypto_pk_rsa_alt_decrypt_func decrypt_func,
+ mbedcrypto_pk_rsa_alt_sign_func sign_func,
+ mbedcrypto_pk_rsa_alt_key_len_func key_len_func )
+{
+ mbedcrypto_rsa_alt_context *rsa_alt;
+ const mbedcrypto_pk_info_t *info = &mbedcrypto_rsa_alt_info;
+
+ if( ctx == NULL || ctx->pk_info != NULL )
+ return( MBEDCRYPTO_ERR_PK_BAD_INPUT_DATA );
+
+ if( ( ctx->pk_ctx = info->ctx_alloc_func() ) == NULL )
+ return( MBEDCRYPTO_ERR_PK_ALLOC_FAILED );
+
+ ctx->pk_info = info;
+
+ rsa_alt = (mbedcrypto_rsa_alt_context *) ctx->pk_ctx;
+
+ rsa_alt->key = key;
+ rsa_alt->decrypt_func = decrypt_func;
+ rsa_alt->sign_func = sign_func;
+ rsa_alt->key_len_func = key_len_func;
+
+ return( 0 );
+}
+#endif /* MBEDCRYPTO_PK_RSA_ALT_SUPPORT */
+
+/*
+ * Tell if a PK can do the operations of the given type
+ */
+int mbedcrypto_pk_can_do( const mbedcrypto_pk_context *ctx, mbedcrypto_pk_type_t type )
+{
+ /* null or NONE context can't do anything */
+ if( ctx == NULL || ctx->pk_info == NULL )
+ return( 0 );
+
+ return( ctx->pk_info->can_do( type ) );
+}
+
+/*
+ * Helper for mbedcrypto_pk_sign and mbedcrypto_pk_verify
+ */
+static inline int pk_hashlen_helper( mbedcrypto_md_type_t md_alg, size_t *hash_len )
+{
+ const mbedcrypto_md_info_t *md_info;
+
+ if( *hash_len != 0 )
+ return( 0 );
+
+ if( ( md_info = mbedcrypto_md_info_from_type( md_alg ) ) == NULL )
+ return( -1 );
+
+ *hash_len = mbedcrypto_md_get_size( md_info );
+ return( 0 );
+}
+
+/*
+ * Verify a signature
+ */
+int mbedcrypto_pk_verify( mbedcrypto_pk_context *ctx, mbedcrypto_md_type_t md_alg,
+ const unsigned char *hash, size_t hash_len,
+ const unsigned char *sig, size_t sig_len )
+{
+ if( ctx == NULL || ctx->pk_info == NULL ||
+ pk_hashlen_helper( md_alg, &hash_len ) != 0 )
+ return( MBEDCRYPTO_ERR_PK_BAD_INPUT_DATA );
+
+ if( ctx->pk_info->verify_func == NULL )
+ return( MBEDCRYPTO_ERR_PK_TYPE_MISMATCH );
+
+ return( ctx->pk_info->verify_func( ctx->pk_ctx, md_alg, hash, hash_len,
+ sig, sig_len ) );
+}
+
+/*
+ * Verify a signature with options
+ */
+int mbedcrypto_pk_verify_ext( mbedcrypto_pk_type_t type, const void *options,
+ mbedcrypto_pk_context *ctx, mbedcrypto_md_type_t md_alg,
+ const unsigned char *hash, size_t hash_len,
+ const unsigned char *sig, size_t sig_len )
+{
+ if( ctx == NULL || ctx->pk_info == NULL )
+ return( MBEDCRYPTO_ERR_PK_BAD_INPUT_DATA );
+
+ if( ! mbedcrypto_pk_can_do( ctx, type ) )
+ return( MBEDCRYPTO_ERR_PK_TYPE_MISMATCH );
+
+ if( type == MBEDCRYPTO_PK_RSASSA_PSS )
+ {
+#if defined(MBEDCRYPTO_RSA_C) && defined(MBEDCRYPTO_PKCS1_V21)
+ int ret;
+ const mbedcrypto_pk_rsassa_pss_options *pss_opts;
+
+#if SIZE_MAX > UINT_MAX
+ if( md_alg == MBEDCRYPTO_MD_NONE && UINT_MAX < hash_len )
+ return( MBEDCRYPTO_ERR_PK_BAD_INPUT_DATA );
+#endif /* SIZE_MAX > UINT_MAX */
+
+ if( options == NULL )
+ return( MBEDCRYPTO_ERR_PK_BAD_INPUT_DATA );
+
+ pss_opts = (const mbedcrypto_pk_rsassa_pss_options *) options;
+
+ if( sig_len < mbedcrypto_pk_get_len( ctx ) )
+ return( MBEDCRYPTO_ERR_RSA_VERIFY_FAILED );
+
+ ret = mbedcrypto_rsa_rsassa_pss_verify_ext( mbedcrypto_pk_rsa( *ctx ),
+ NULL, NULL, MBEDCRYPTO_RSA_PUBLIC,
+ md_alg, (unsigned int) hash_len, hash,
+ pss_opts->mgf1_hash_id,
+ pss_opts->expected_salt_len,
+ sig );
+ if( ret != 0 )
+ return( ret );
+
+ if( sig_len > mbedcrypto_pk_get_len( ctx ) )
+ return( MBEDCRYPTO_ERR_PK_SIG_LEN_MISMATCH );
+
+ return( 0 );
+#else
+ return( MBEDCRYPTO_ERR_PK_FEATURE_UNAVAILABLE );
+#endif /* MBEDCRYPTO_RSA_C && MBEDCRYPTO_PKCS1_V21 */
+ }
+
+ /* General case: no options */
+ if( options != NULL )
+ return( MBEDCRYPTO_ERR_PK_BAD_INPUT_DATA );
+
+ return( mbedcrypto_pk_verify( ctx, md_alg, hash, hash_len, sig, sig_len ) );
+}
+
+/*
+ * Make a signature
+ */
+int mbedcrypto_pk_sign( mbedcrypto_pk_context *ctx, mbedcrypto_md_type_t md_alg,
+ const unsigned char *hash, size_t hash_len,
+ unsigned char *sig, size_t *sig_len,
+ int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
+{
+ if( ctx == NULL || ctx->pk_info == NULL ||
+ pk_hashlen_helper( md_alg, &hash_len ) != 0 )
+ return( MBEDCRYPTO_ERR_PK_BAD_INPUT_DATA );
+
+ if( ctx->pk_info->sign_func == NULL )
+ return( MBEDCRYPTO_ERR_PK_TYPE_MISMATCH );
+
+ return( ctx->pk_info->sign_func( ctx->pk_ctx, md_alg, hash, hash_len,
+ sig, sig_len, f_rng, p_rng ) );
+}
+
+/*
+ * Decrypt message
+ */
+int mbedcrypto_pk_decrypt( mbedcrypto_pk_context *ctx,
+ const unsigned char *input, size_t ilen,
+ unsigned char *output, size_t *olen, size_t osize,
+ int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
+{
+ if( ctx == NULL || ctx->pk_info == NULL )
+ return( MBEDCRYPTO_ERR_PK_BAD_INPUT_DATA );
+
+ if( ctx->pk_info->decrypt_func == NULL )
+ return( MBEDCRYPTO_ERR_PK_TYPE_MISMATCH );
+
+ return( ctx->pk_info->decrypt_func( ctx->pk_ctx, input, ilen,
+ output, olen, osize, f_rng, p_rng ) );
+}
+
+/*
+ * Encrypt message
+ */
+int mbedcrypto_pk_encrypt( mbedcrypto_pk_context *ctx,
+ const unsigned char *input, size_t ilen,
+ unsigned char *output, size_t *olen, size_t osize,
+ int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
+{
+ if( ctx == NULL || ctx->pk_info == NULL )
+ return( MBEDCRYPTO_ERR_PK_BAD_INPUT_DATA );
+
+ if( ctx->pk_info->encrypt_func == NULL )
+ return( MBEDCRYPTO_ERR_PK_TYPE_MISMATCH );
+
+ return( ctx->pk_info->encrypt_func( ctx->pk_ctx, input, ilen,
+ output, olen, osize, f_rng, p_rng ) );
+}
+
+/*
+ * Check public-private key pair
+ */
+int mbedcrypto_pk_check_pair( const mbedcrypto_pk_context *pub, const mbedcrypto_pk_context *prv )
+{
+ if( pub == NULL || pub->pk_info == NULL ||
+ prv == NULL || prv->pk_info == NULL ||
+ prv->pk_info->check_pair_func == NULL )
+ {
+ return( MBEDCRYPTO_ERR_PK_BAD_INPUT_DATA );
+ }
+
+ if( prv->pk_info->type == MBEDCRYPTO_PK_RSA_ALT )
+ {
+ if( pub->pk_info->type != MBEDCRYPTO_PK_RSA )
+ return( MBEDCRYPTO_ERR_PK_TYPE_MISMATCH );
+ }
+ else
+ {
+ if( pub->pk_info != prv->pk_info )
+ return( MBEDCRYPTO_ERR_PK_TYPE_MISMATCH );
+ }
+
+ return( prv->pk_info->check_pair_func( pub->pk_ctx, prv->pk_ctx ) );
+}
+
+/*
+ * Get key size in bits
+ */
+size_t mbedcrypto_pk_get_bitlen( const mbedcrypto_pk_context *ctx )
+{
+ if( ctx == NULL || ctx->pk_info == NULL )
+ return( 0 );
+
+ return( ctx->pk_info->get_bitlen( ctx->pk_ctx ) );
+}
+
+/*
+ * Export debug information
+ */
+int mbedcrypto_pk_debug( const mbedcrypto_pk_context *ctx, mbedcrypto_pk_debug_item *items )
+{
+ if( ctx == NULL || ctx->pk_info == NULL )
+ return( MBEDCRYPTO_ERR_PK_BAD_INPUT_DATA );
+
+ if( ctx->pk_info->debug_func == NULL )
+ return( MBEDCRYPTO_ERR_PK_TYPE_MISMATCH );
+
+ ctx->pk_info->debug_func( ctx->pk_ctx, items );
+ return( 0 );
+}
+
+/*
+ * Access the PK type name
+ */
+const char *mbedcrypto_pk_get_name( const mbedcrypto_pk_context *ctx )
+{
+ if( ctx == NULL || ctx->pk_info == NULL )
+ return( "invalid PK" );
+
+ return( ctx->pk_info->name );
+}
+
+/*
+ * Access the PK type
+ */
+mbedcrypto_pk_type_t mbedcrypto_pk_get_type( const mbedcrypto_pk_context *ctx )
+{
+ if( ctx == NULL || ctx->pk_info == NULL )
+ return( MBEDCRYPTO_PK_NONE );
+
+ return( ctx->pk_info->type );
+}
+
+#endif /* MBEDCRYPTO_PK_C */
diff --git a/library/pk_wrap.c b/library/pk_wrap.c
new file mode 100644
index 0000000..987244c
--- /dev/null
+++ b/library/pk_wrap.c
@@ -0,0 +1,523 @@
+/*
+ * Public Key abstraction layer: wrapper 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 Crypto (https://tls.mbed.org)
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_PK_C)
+#include "mbedcrypto/pk_internal.h"
+
+/* Even if RSA not activated, for the sake of RSA-alt */
+#include "mbedcrypto/rsa.h"
+
+#include <string.h>
+
+#if defined(MBEDCRYPTO_ECP_C)
+#include "mbedcrypto/ecp.h"
+#endif
+
+#if defined(MBEDCRYPTO_ECDSA_C)
+#include "mbedcrypto/ecdsa.h"
+#endif
+
+#if defined(MBEDCRYPTO_PK_RSA_ALT_SUPPORT)
+#include "mbedcrypto/platform_util.h"
+#endif
+
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#include <stdlib.h>
+#define mbedcrypto_calloc calloc
+#define mbedcrypto_free free
+#endif
+
+#include <limits.h>
+#include <stdint.h>
+
+#if defined(MBEDCRYPTO_RSA_C)
+static int rsa_can_do( mbedcrypto_pk_type_t type )
+{
+ return( type == MBEDCRYPTO_PK_RSA ||
+ type == MBEDCRYPTO_PK_RSASSA_PSS );
+}
+
+static size_t rsa_get_bitlen( const void *ctx )
+{
+ const mbedcrypto_rsa_context * rsa = (const mbedcrypto_rsa_context *) ctx;
+ return( mbedcrypto_rsa_get_bitlen( rsa ) );
+}
+
+static int rsa_verify_wrap( void *ctx, mbedcrypto_md_type_t md_alg,
+ const unsigned char *hash, size_t hash_len,
+ const unsigned char *sig, size_t sig_len )
+{
+ int ret;
+ mbedcrypto_rsa_context * rsa = (mbedcrypto_rsa_context *) ctx;
+ size_t rsa_len = mbedcrypto_rsa_get_len( rsa );
+
+#if SIZE_MAX > UINT_MAX
+ if( md_alg == MBEDCRYPTO_MD_NONE && UINT_MAX < hash_len )
+ return( MBEDCRYPTO_ERR_PK_BAD_INPUT_DATA );
+#endif /* SIZE_MAX > UINT_MAX */
+
+ if( sig_len < rsa_len )
+ return( MBEDCRYPTO_ERR_RSA_VERIFY_FAILED );
+
+ if( ( ret = mbedcrypto_rsa_pkcs1_verify( rsa, NULL, NULL,
+ MBEDCRYPTO_RSA_PUBLIC, md_alg,
+ (unsigned int) hash_len, hash, sig ) ) != 0 )
+ return( ret );
+
+ /* The buffer contains a valid signature followed by extra data.
+ * We have a special error code for that so that so that callers can
+ * use mbedcrypto_pk_verify() to check "Does the buffer start with a
+ * valid signature?" and not just "Does the buffer contain a valid
+ * signature?". */
+ if( sig_len > rsa_len )
+ return( MBEDCRYPTO_ERR_PK_SIG_LEN_MISMATCH );
+
+ return( 0 );
+}
+
+static int rsa_sign_wrap( void *ctx, mbedcrypto_md_type_t md_alg,
+ const unsigned char *hash, size_t hash_len,
+ unsigned char *sig, size_t *sig_len,
+ int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
+{
+ mbedcrypto_rsa_context * rsa = (mbedcrypto_rsa_context *) ctx;
+
+#if SIZE_MAX > UINT_MAX
+ if( md_alg == MBEDCRYPTO_MD_NONE && UINT_MAX < hash_len )
+ return( MBEDCRYPTO_ERR_PK_BAD_INPUT_DATA );
+#endif /* SIZE_MAX > UINT_MAX */
+
+ *sig_len = mbedcrypto_rsa_get_len( rsa );
+
+ return( mbedcrypto_rsa_pkcs1_sign( rsa, f_rng, p_rng, MBEDCRYPTO_RSA_PRIVATE,
+ md_alg, (unsigned int) hash_len, hash, sig ) );
+}
+
+static int rsa_decrypt_wrap( void *ctx,
+ const unsigned char *input, size_t ilen,
+ unsigned char *output, size_t *olen, size_t osize,
+ int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
+{
+ mbedcrypto_rsa_context * rsa = (mbedcrypto_rsa_context *) ctx;
+
+ if( ilen != mbedcrypto_rsa_get_len( rsa ) )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ return( mbedcrypto_rsa_pkcs1_decrypt( rsa, f_rng, p_rng,
+ MBEDCRYPTO_RSA_PRIVATE, olen, input, output, osize ) );
+}
+
+static int rsa_encrypt_wrap( void *ctx,
+ const unsigned char *input, size_t ilen,
+ unsigned char *output, size_t *olen, size_t osize,
+ int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
+{
+ mbedcrypto_rsa_context * rsa = (mbedcrypto_rsa_context *) ctx;
+ *olen = mbedcrypto_rsa_get_len( rsa );
+
+ if( *olen > osize )
+ return( MBEDCRYPTO_ERR_RSA_OUTPUT_TOO_LARGE );
+
+ return( mbedcrypto_rsa_pkcs1_encrypt( rsa, f_rng, p_rng, MBEDCRYPTO_RSA_PUBLIC,
+ ilen, input, output ) );
+}
+
+static int rsa_check_pair_wrap( const void *pub, const void *prv )
+{
+ return( mbedcrypto_rsa_check_pub_priv( (const mbedcrypto_rsa_context *) pub,
+ (const mbedcrypto_rsa_context *) prv ) );
+}
+
+static void *rsa_alloc_wrap( void )
+{
+ void *ctx = mbedcrypto_calloc( 1, sizeof( mbedcrypto_rsa_context ) );
+
+ if( ctx != NULL )
+ mbedcrypto_rsa_init( (mbedcrypto_rsa_context *) ctx, 0, 0 );
+
+ return( ctx );
+}
+
+static void rsa_free_wrap( void *ctx )
+{
+ mbedcrypto_rsa_free( (mbedcrypto_rsa_context *) ctx );
+ mbedcrypto_free( ctx );
+}
+
+static void rsa_debug( const void *ctx, mbedcrypto_pk_debug_item *items )
+{
+ items->type = MBEDCRYPTO_PK_DEBUG_MPI;
+ items->name = "rsa.N";
+ items->value = &( ((mbedcrypto_rsa_context *) ctx)->N );
+
+ items++;
+
+ items->type = MBEDCRYPTO_PK_DEBUG_MPI;
+ items->name = "rsa.E";
+ items->value = &( ((mbedcrypto_rsa_context *) ctx)->E );
+}
+
+const mbedcrypto_pk_info_t mbedcrypto_rsa_info = {
+ MBEDCRYPTO_PK_RSA,
+ "RSA",
+ rsa_get_bitlen,
+ rsa_can_do,
+ rsa_verify_wrap,
+ rsa_sign_wrap,
+ rsa_decrypt_wrap,
+ rsa_encrypt_wrap,
+ rsa_check_pair_wrap,
+ rsa_alloc_wrap,
+ rsa_free_wrap,
+ rsa_debug,
+};
+#endif /* MBEDCRYPTO_RSA_C */
+
+#if defined(MBEDCRYPTO_ECP_C)
+/*
+ * Generic EC key
+ */
+static int eckey_can_do( mbedcrypto_pk_type_t type )
+{
+ return( type == MBEDCRYPTO_PK_ECKEY ||
+ type == MBEDCRYPTO_PK_ECKEY_DH ||
+ type == MBEDCRYPTO_PK_ECDSA );
+}
+
+static size_t eckey_get_bitlen( const void *ctx )
+{
+ return( ((mbedcrypto_ecp_keypair *) ctx)->grp.pbits );
+}
+
+#if defined(MBEDCRYPTO_ECDSA_C)
+/* Forward declarations */
+static int ecdsa_verify_wrap( void *ctx, mbedcrypto_md_type_t md_alg,
+ const unsigned char *hash, size_t hash_len,
+ const unsigned char *sig, size_t sig_len );
+
+static int ecdsa_sign_wrap( void *ctx, mbedcrypto_md_type_t md_alg,
+ const unsigned char *hash, size_t hash_len,
+ unsigned char *sig, size_t *sig_len,
+ int (*f_rng)(void *, unsigned char *, size_t), void *p_rng );
+
+static int eckey_verify_wrap( void *ctx, mbedcrypto_md_type_t md_alg,
+ const unsigned char *hash, size_t hash_len,
+ const unsigned char *sig, size_t sig_len )
+{
+ int ret;
+ mbedcrypto_ecdsa_context ecdsa;
+
+ mbedcrypto_ecdsa_init( &ecdsa );
+
+ if( ( ret = mbedcrypto_ecdsa_from_keypair( &ecdsa, ctx ) ) == 0 )
+ ret = ecdsa_verify_wrap( &ecdsa, md_alg, hash, hash_len, sig, sig_len );
+
+ mbedcrypto_ecdsa_free( &ecdsa );
+
+ return( ret );
+}
+
+static int eckey_sign_wrap( void *ctx, mbedcrypto_md_type_t md_alg,
+ const unsigned char *hash, size_t hash_len,
+ unsigned char *sig, size_t *sig_len,
+ int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
+{
+ int ret;
+ mbedcrypto_ecdsa_context ecdsa;
+
+ mbedcrypto_ecdsa_init( &ecdsa );
+
+ if( ( ret = mbedcrypto_ecdsa_from_keypair( &ecdsa, ctx ) ) == 0 )
+ ret = ecdsa_sign_wrap( &ecdsa, md_alg, hash, hash_len, sig, sig_len,
+ f_rng, p_rng );
+
+ mbedcrypto_ecdsa_free( &ecdsa );
+
+ return( ret );
+}
+
+#endif /* MBEDCRYPTO_ECDSA_C */
+
+static int eckey_check_pair( const void *pub, const void *prv )
+{
+ return( mbedcrypto_ecp_check_pub_priv( (const mbedcrypto_ecp_keypair *) pub,
+ (const mbedcrypto_ecp_keypair *) prv ) );
+}
+
+static void *eckey_alloc_wrap( void )
+{
+ void *ctx = mbedcrypto_calloc( 1, sizeof( mbedcrypto_ecp_keypair ) );
+
+ if( ctx != NULL )
+ mbedcrypto_ecp_keypair_init( ctx );
+
+ return( ctx );
+}
+
+static void eckey_free_wrap( void *ctx )
+{
+ mbedcrypto_ecp_keypair_free( (mbedcrypto_ecp_keypair *) ctx );
+ mbedcrypto_free( ctx );
+}
+
+static void eckey_debug( const void *ctx, mbedcrypto_pk_debug_item *items )
+{
+ items->type = MBEDCRYPTO_PK_DEBUG_ECP;
+ items->name = "eckey.Q";
+ items->value = &( ((mbedcrypto_ecp_keypair *) ctx)->Q );
+}
+
+const mbedcrypto_pk_info_t mbedcrypto_eckey_info = {
+ MBEDCRYPTO_PK_ECKEY,
+ "EC",
+ eckey_get_bitlen,
+ eckey_can_do,
+#if defined(MBEDCRYPTO_ECDSA_C)
+ eckey_verify_wrap,
+ eckey_sign_wrap,
+#else
+ NULL,
+ NULL,
+#endif
+ NULL,
+ NULL,
+ eckey_check_pair,
+ eckey_alloc_wrap,
+ eckey_free_wrap,
+ eckey_debug,
+};
+
+/*
+ * EC key restricted to ECDH
+ */
+static int eckeydh_can_do( mbedcrypto_pk_type_t type )
+{
+ return( type == MBEDCRYPTO_PK_ECKEY ||
+ type == MBEDCRYPTO_PK_ECKEY_DH );
+}
+
+const mbedcrypto_pk_info_t mbedcrypto_eckeydh_info = {
+ MBEDCRYPTO_PK_ECKEY_DH,
+ "EC_DH",
+ eckey_get_bitlen, /* Same underlying key structure */
+ eckeydh_can_do,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ eckey_check_pair,
+ eckey_alloc_wrap, /* Same underlying key structure */
+ eckey_free_wrap, /* Same underlying key structure */
+ eckey_debug, /* Same underlying key structure */
+};
+#endif /* MBEDCRYPTO_ECP_C */
+
+#if defined(MBEDCRYPTO_ECDSA_C)
+static int ecdsa_can_do( mbedcrypto_pk_type_t type )
+{
+ return( type == MBEDCRYPTO_PK_ECDSA );
+}
+
+static int ecdsa_verify_wrap( void *ctx, mbedcrypto_md_type_t md_alg,
+ const unsigned char *hash, size_t hash_len,
+ const unsigned char *sig, size_t sig_len )
+{
+ int ret;
+ ((void) md_alg);
+
+ ret = mbedcrypto_ecdsa_read_signature( (mbedcrypto_ecdsa_context *) ctx,
+ hash, hash_len, sig, sig_len );
+
+ if( ret == MBEDCRYPTO_ERR_ECP_SIG_LEN_MISMATCH )
+ return( MBEDCRYPTO_ERR_PK_SIG_LEN_MISMATCH );
+
+ return( ret );
+}
+
+static int ecdsa_sign_wrap( void *ctx, mbedcrypto_md_type_t md_alg,
+ const unsigned char *hash, size_t hash_len,
+ unsigned char *sig, size_t *sig_len,
+ int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
+{
+ return( mbedcrypto_ecdsa_write_signature( (mbedcrypto_ecdsa_context *) ctx,
+ md_alg, hash, hash_len, sig, sig_len, f_rng, p_rng ) );
+}
+
+static void *ecdsa_alloc_wrap( void )
+{
+ void *ctx = mbedcrypto_calloc( 1, sizeof( mbedcrypto_ecdsa_context ) );
+
+ if( ctx != NULL )
+ mbedcrypto_ecdsa_init( (mbedcrypto_ecdsa_context *) ctx );
+
+ return( ctx );
+}
+
+static void ecdsa_free_wrap( void *ctx )
+{
+ mbedcrypto_ecdsa_free( (mbedcrypto_ecdsa_context *) ctx );
+ mbedcrypto_free( ctx );
+}
+
+const mbedcrypto_pk_info_t mbedcrypto_ecdsa_info = {
+ MBEDCRYPTO_PK_ECDSA,
+ "ECDSA",
+ eckey_get_bitlen, /* Compatible key structures */
+ ecdsa_can_do,
+ ecdsa_verify_wrap,
+ ecdsa_sign_wrap,
+ NULL,
+ NULL,
+ eckey_check_pair, /* Compatible key structures */
+ ecdsa_alloc_wrap,
+ ecdsa_free_wrap,
+ eckey_debug, /* Compatible key structures */
+};
+#endif /* MBEDCRYPTO_ECDSA_C */
+
+#if defined(MBEDCRYPTO_PK_RSA_ALT_SUPPORT)
+/*
+ * Support for alternative RSA-private implementations
+ */
+
+static int rsa_alt_can_do( mbedcrypto_pk_type_t type )
+{
+ return( type == MBEDCRYPTO_PK_RSA );
+}
+
+static size_t rsa_alt_get_bitlen( const void *ctx )
+{
+ const mbedcrypto_rsa_alt_context *rsa_alt = (const mbedcrypto_rsa_alt_context *) ctx;
+
+ return( 8 * rsa_alt->key_len_func( rsa_alt->key ) );
+}
+
+static int rsa_alt_sign_wrap( void *ctx, mbedcrypto_md_type_t md_alg,
+ const unsigned char *hash, size_t hash_len,
+ unsigned char *sig, size_t *sig_len,
+ int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
+{
+ mbedcrypto_rsa_alt_context *rsa_alt = (mbedcrypto_rsa_alt_context *) ctx;
+
+#if SIZE_MAX > UINT_MAX
+ if( UINT_MAX < hash_len )
+ return( MBEDCRYPTO_ERR_PK_BAD_INPUT_DATA );
+#endif /* SIZE_MAX > UINT_MAX */
+
+ *sig_len = rsa_alt->key_len_func( rsa_alt->key );
+
+ return( rsa_alt->sign_func( rsa_alt->key, f_rng, p_rng, MBEDCRYPTO_RSA_PRIVATE,
+ md_alg, (unsigned int) hash_len, hash, sig ) );
+}
+
+static int rsa_alt_decrypt_wrap( void *ctx,
+ const unsigned char *input, size_t ilen,
+ unsigned char *output, size_t *olen, size_t osize,
+ int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
+{
+ mbedcrypto_rsa_alt_context *rsa_alt = (mbedcrypto_rsa_alt_context *) ctx;
+
+ ((void) f_rng);
+ ((void) p_rng);
+
+ if( ilen != rsa_alt->key_len_func( rsa_alt->key ) )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ return( rsa_alt->decrypt_func( rsa_alt->key,
+ MBEDCRYPTO_RSA_PRIVATE, olen, input, output, osize ) );
+}
+
+#if defined(MBEDCRYPTO_RSA_C)
+static int rsa_alt_check_pair( const void *pub, const void *prv )
+{
+ unsigned char sig[MBEDCRYPTO_MPI_MAX_SIZE];
+ unsigned char hash[32];
+ size_t sig_len = 0;
+ int ret;
+
+ if( rsa_alt_get_bitlen( prv ) != rsa_get_bitlen( pub ) )
+ return( MBEDCRYPTO_ERR_RSA_KEY_CHECK_FAILED );
+
+ memset( hash, 0x2a, sizeof( hash ) );
+
+ if( ( ret = rsa_alt_sign_wrap( (void *) prv, MBEDCRYPTO_MD_NONE,
+ hash, sizeof( hash ),
+ sig, &sig_len, NULL, NULL ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ if( rsa_verify_wrap( (void *) pub, MBEDCRYPTO_MD_NONE,
+ hash, sizeof( hash ), sig, sig_len ) != 0 )
+ {
+ return( MBEDCRYPTO_ERR_RSA_KEY_CHECK_FAILED );
+ }
+
+ return( 0 );
+}
+#endif /* MBEDCRYPTO_RSA_C */
+
+static void *rsa_alt_alloc_wrap( void )
+{
+ void *ctx = mbedcrypto_calloc( 1, sizeof( mbedcrypto_rsa_alt_context ) );
+
+ if( ctx != NULL )
+ memset( ctx, 0, sizeof( mbedcrypto_rsa_alt_context ) );
+
+ return( ctx );
+}
+
+static void rsa_alt_free_wrap( void *ctx )
+{
+ mbedcrypto_platform_zeroize( ctx, sizeof( mbedcrypto_rsa_alt_context ) );
+ mbedcrypto_free( ctx );
+}
+
+const mbedcrypto_pk_info_t mbedcrypto_rsa_alt_info = {
+ MBEDCRYPTO_PK_RSA_ALT,
+ "RSA-alt",
+ rsa_alt_get_bitlen,
+ rsa_alt_can_do,
+ NULL,
+ rsa_alt_sign_wrap,
+ rsa_alt_decrypt_wrap,
+ NULL,
+#if defined(MBEDCRYPTO_RSA_C)
+ rsa_alt_check_pair,
+#else
+ NULL,
+#endif
+ rsa_alt_alloc_wrap,
+ rsa_alt_free_wrap,
+ NULL,
+};
+
+#endif /* MBEDCRYPTO_PK_RSA_ALT_SUPPORT */
+
+#endif /* MBEDCRYPTO_PK_C */
diff --git a/library/pkcs12.c b/library/pkcs12.c
new file mode 100644
index 0000000..ccebd4d
--- /dev/null
+++ b/library/pkcs12.c
@@ -0,0 +1,361 @@
+/*
+ * PKCS#12 Personal Information Exchange Syntax
+ *
+ * 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 Crypto (https://tls.mbed.org)
+ */
+/*
+ * The PKCS #12 Personal Information Exchange Syntax Standard v1.1
+ *
+ * http://www.rsa.com/rsalabs/pkcs/files/h11301-wp-pkcs-12v1-1-personal-information-exchange-syntax.pdf
+ * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1-1.asn
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_PKCS12_C)
+
+#include "mbedcrypto/pkcs12.h"
+#include "mbedcrypto/asn1.h"
+#include "mbedcrypto/cipher.h"
+#include "mbedcrypto/platform_util.h"
+
+#include <string.h>
+
+#if defined(MBEDCRYPTO_ARC4_C)
+#include "mbedcrypto/arc4.h"
+#endif
+
+#if defined(MBEDCRYPTO_DES_C)
+#include "mbedcrypto/des.h"
+#endif
+
+static int pkcs12_parse_pbe_params( mbedcrypto_asn1_buf *params,
+ mbedcrypto_asn1_buf *salt, int *iterations )
+{
+ int ret;
+ unsigned char **p = ¶ms->p;
+ const unsigned char *end = params->p + params->len;
+
+ /*
+ * pkcs-12PbeParams ::= SEQUENCE {
+ * salt OCTET STRING,
+ * iterations INTEGER
+ * }
+ *
+ */
+ if( params->tag != ( MBEDCRYPTO_ASN1_CONSTRUCTED | MBEDCRYPTO_ASN1_SEQUENCE ) )
+ return( MBEDCRYPTO_ERR_PKCS12_PBE_INVALID_FORMAT +
+ MBEDCRYPTO_ERR_ASN1_UNEXPECTED_TAG );
+
+ if( ( ret = mbedcrypto_asn1_get_tag( p, end, &salt->len, MBEDCRYPTO_ASN1_OCTET_STRING ) ) != 0 )
+ return( MBEDCRYPTO_ERR_PKCS12_PBE_INVALID_FORMAT + ret );
+
+ salt->p = *p;
+ *p += salt->len;
+
+ if( ( ret = mbedcrypto_asn1_get_int( p, end, iterations ) ) != 0 )
+ return( MBEDCRYPTO_ERR_PKCS12_PBE_INVALID_FORMAT + ret );
+
+ if( *p != end )
+ return( MBEDCRYPTO_ERR_PKCS12_PBE_INVALID_FORMAT +
+ MBEDCRYPTO_ERR_ASN1_LENGTH_MISMATCH );
+
+ return( 0 );
+}
+
+#define PKCS12_MAX_PWDLEN 128
+
+static int pkcs12_pbe_derive_key_iv( mbedcrypto_asn1_buf *pbe_params, mbedcrypto_md_type_t md_type,
+ const unsigned char *pwd, size_t pwdlen,
+ unsigned char *key, size_t keylen,
+ unsigned char *iv, size_t ivlen )
+{
+ int ret, iterations = 0;
+ mbedcrypto_asn1_buf salt;
+ size_t i;
+ unsigned char unipwd[PKCS12_MAX_PWDLEN * 2 + 2];
+
+ if( pwdlen > PKCS12_MAX_PWDLEN )
+ return( MBEDCRYPTO_ERR_PKCS12_BAD_INPUT_DATA );
+
+ memset( &salt, 0, sizeof(mbedcrypto_asn1_buf) );
+ memset( &unipwd, 0, sizeof(unipwd) );
+
+ if( ( ret = pkcs12_parse_pbe_params( pbe_params, &salt,
+ &iterations ) ) != 0 )
+ return( ret );
+
+ for( i = 0; i < pwdlen; i++ )
+ unipwd[i * 2 + 1] = pwd[i];
+
+ if( ( ret = mbedcrypto_pkcs12_derivation( key, keylen, unipwd, pwdlen * 2 + 2,
+ salt.p, salt.len, md_type,
+ MBEDCRYPTO_PKCS12_DERIVE_KEY, iterations ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ if( iv == NULL || ivlen == 0 )
+ return( 0 );
+
+ if( ( ret = mbedcrypto_pkcs12_derivation( iv, ivlen, unipwd, pwdlen * 2 + 2,
+ salt.p, salt.len, md_type,
+ MBEDCRYPTO_PKCS12_DERIVE_IV, iterations ) ) != 0 )
+ {
+ return( ret );
+ }
+ return( 0 );
+}
+
+#undef PKCS12_MAX_PWDLEN
+
+int mbedcrypto_pkcs12_pbe_sha1_rc4_128( mbedcrypto_asn1_buf *pbe_params, int mode,
+ const unsigned char *pwd, size_t pwdlen,
+ const unsigned char *data, size_t len,
+ unsigned char *output )
+{
+#if !defined(MBEDCRYPTO_ARC4_C)
+ ((void) pbe_params);
+ ((void) mode);
+ ((void) pwd);
+ ((void) pwdlen);
+ ((void) data);
+ ((void) len);
+ ((void) output);
+ return( MBEDCRYPTO_ERR_PKCS12_FEATURE_UNAVAILABLE );
+#else
+ int ret;
+ unsigned char key[16];
+ mbedcrypto_arc4_context ctx;
+ ((void) mode);
+
+ mbedcrypto_arc4_init( &ctx );
+
+ if( ( ret = pkcs12_pbe_derive_key_iv( pbe_params, MBEDCRYPTO_MD_SHA1,
+ pwd, pwdlen,
+ key, 16, NULL, 0 ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ mbedcrypto_arc4_setup( &ctx, key, 16 );
+ if( ( ret = mbedcrypto_arc4_crypt( &ctx, len, data, output ) ) != 0 )
+ goto exit;
+
+exit:
+ mbedcrypto_platform_zeroize( key, sizeof( key ) );
+ mbedcrypto_arc4_free( &ctx );
+
+ return( ret );
+#endif /* MBEDCRYPTO_ARC4_C */
+}
+
+int mbedcrypto_pkcs12_pbe( mbedcrypto_asn1_buf *pbe_params, int mode,
+ mbedcrypto_cipher_type_t cipher_type, mbedcrypto_md_type_t md_type,
+ const unsigned char *pwd, size_t pwdlen,
+ const unsigned char *data, size_t len,
+ unsigned char *output )
+{
+ int ret, keylen = 0;
+ unsigned char key[32];
+ unsigned char iv[16];
+ const mbedcrypto_cipher_info_t *cipher_info;
+ mbedcrypto_cipher_context_t cipher_ctx;
+ size_t olen = 0;
+
+ cipher_info = mbedcrypto_cipher_info_from_type( cipher_type );
+ if( cipher_info == NULL )
+ return( MBEDCRYPTO_ERR_PKCS12_FEATURE_UNAVAILABLE );
+
+ keylen = cipher_info->key_bitlen / 8;
+
+ if( ( ret = pkcs12_pbe_derive_key_iv( pbe_params, md_type, pwd, pwdlen,
+ key, keylen,
+ iv, cipher_info->iv_size ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ mbedcrypto_cipher_init( &cipher_ctx );
+
+ if( ( ret = mbedcrypto_cipher_setup( &cipher_ctx, cipher_info ) ) != 0 )
+ goto exit;
+
+ if( ( ret = mbedcrypto_cipher_setkey( &cipher_ctx, key, 8 * keylen, (mbedcrypto_operation_t) mode ) ) != 0 )
+ goto exit;
+
+ if( ( ret = mbedcrypto_cipher_set_iv( &cipher_ctx, iv, cipher_info->iv_size ) ) != 0 )
+ goto exit;
+
+ if( ( ret = mbedcrypto_cipher_reset( &cipher_ctx ) ) != 0 )
+ goto exit;
+
+ if( ( ret = mbedcrypto_cipher_update( &cipher_ctx, data, len,
+ output, &olen ) ) != 0 )
+ {
+ goto exit;
+ }
+
+ if( ( ret = mbedcrypto_cipher_finish( &cipher_ctx, output + olen, &olen ) ) != 0 )
+ ret = MBEDCRYPTO_ERR_PKCS12_PASSWORD_MISMATCH;
+
+exit:
+ mbedcrypto_platform_zeroize( key, sizeof( key ) );
+ mbedcrypto_platform_zeroize( iv, sizeof( iv ) );
+ mbedcrypto_cipher_free( &cipher_ctx );
+
+ return( ret );
+}
+
+static void pkcs12_fill_buffer( unsigned char *data, size_t data_len,
+ const unsigned char *filler, size_t fill_len )
+{
+ unsigned char *p = data;
+ size_t use_len;
+
+ while( data_len > 0 )
+ {
+ use_len = ( data_len > fill_len ) ? fill_len : data_len;
+ memcpy( p, filler, use_len );
+ p += use_len;
+ data_len -= use_len;
+ }
+}
+
+int mbedcrypto_pkcs12_derivation( unsigned char *data, size_t datalen,
+ const unsigned char *pwd, size_t pwdlen,
+ const unsigned char *salt, size_t saltlen,
+ mbedcrypto_md_type_t md_type, int id, int iterations )
+{
+ int ret;
+ unsigned int j;
+
+ unsigned char diversifier[128];
+ unsigned char salt_block[128], pwd_block[128], hash_block[128];
+ unsigned char hash_output[MBEDCRYPTO_MD_MAX_SIZE];
+ unsigned char *p;
+ unsigned char c;
+
+ size_t hlen, use_len, v, i;
+
+ const mbedcrypto_md_info_t *md_info;
+ mbedcrypto_md_context_t md_ctx;
+
+ // This version only allows max of 64 bytes of password or salt
+ if( datalen > 128 || pwdlen > 64 || saltlen > 64 )
+ return( MBEDCRYPTO_ERR_PKCS12_BAD_INPUT_DATA );
+
+ md_info = mbedcrypto_md_info_from_type( md_type );
+ if( md_info == NULL )
+ return( MBEDCRYPTO_ERR_PKCS12_FEATURE_UNAVAILABLE );
+
+ mbedcrypto_md_init( &md_ctx );
+
+ if( ( ret = mbedcrypto_md_setup( &md_ctx, md_info, 0 ) ) != 0 )
+ return( ret );
+ hlen = mbedcrypto_md_get_size( md_info );
+
+ if( hlen <= 32 )
+ v = 64;
+ else
+ v = 128;
+
+ memset( diversifier, (unsigned char) id, v );
+
+ pkcs12_fill_buffer( salt_block, v, salt, saltlen );
+ pkcs12_fill_buffer( pwd_block, v, pwd, pwdlen );
+
+ p = data;
+ while( datalen > 0 )
+ {
+ // Calculate hash( diversifier || salt_block || pwd_block )
+ if( ( ret = mbedcrypto_md_starts( &md_ctx ) ) != 0 )
+ goto exit;
+
+ if( ( ret = mbedcrypto_md_update( &md_ctx, diversifier, v ) ) != 0 )
+ goto exit;
+
+ if( ( ret = mbedcrypto_md_update( &md_ctx, salt_block, v ) ) != 0 )
+ goto exit;
+
+ if( ( ret = mbedcrypto_md_update( &md_ctx, pwd_block, v ) ) != 0 )
+ goto exit;
+
+ if( ( ret = mbedcrypto_md_finish( &md_ctx, hash_output ) ) != 0 )
+ goto exit;
+
+ // Perform remaining ( iterations - 1 ) recursive hash calculations
+ for( i = 1; i < (size_t) iterations; i++ )
+ {
+ if( ( ret = mbedcrypto_md( md_info, hash_output, hlen, hash_output ) ) != 0 )
+ goto exit;
+ }
+
+ use_len = ( datalen > hlen ) ? hlen : datalen;
+ memcpy( p, hash_output, use_len );
+ datalen -= use_len;
+ p += use_len;
+
+ if( datalen == 0 )
+ break;
+
+ // Concatenating copies of hash_output into hash_block (B)
+ pkcs12_fill_buffer( hash_block, v, hash_output, hlen );
+
+ // B += 1
+ for( i = v; i > 0; i-- )
+ if( ++hash_block[i - 1] != 0 )
+ break;
+
+ // salt_block += B
+ c = 0;
+ for( i = v; i > 0; i-- )
+ {
+ j = salt_block[i - 1] + hash_block[i - 1] + c;
+ c = (unsigned char) (j >> 8);
+ salt_block[i - 1] = j & 0xFF;
+ }
+
+ // pwd_block += B
+ c = 0;
+ for( i = v; i > 0; i-- )
+ {
+ j = pwd_block[i - 1] + hash_block[i - 1] + c;
+ c = (unsigned char) (j >> 8);
+ pwd_block[i - 1] = j & 0xFF;
+ }
+ }
+
+ ret = 0;
+
+exit:
+ mbedcrypto_platform_zeroize( salt_block, sizeof( salt_block ) );
+ mbedcrypto_platform_zeroize( pwd_block, sizeof( pwd_block ) );
+ mbedcrypto_platform_zeroize( hash_block, sizeof( hash_block ) );
+ mbedcrypto_platform_zeroize( hash_output, sizeof( hash_output ) );
+
+ mbedcrypto_md_free( &md_ctx );
+
+ return( ret );
+}
+
+#endif /* MBEDCRYPTO_PKCS12_C */
diff --git a/library/pkcs5.c b/library/pkcs5.c
new file mode 100644
index 0000000..4467dd7
--- /dev/null
+++ b/library/pkcs5.c
@@ -0,0 +1,424 @@
+/**
+ * \file pkcs5.c
+ *
+ * \brief PKCS#5 functions
+ *
+ * \author Mathias Olsson <mathias@kompetensum.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 Crypto (https://tls.mbed.org)
+ */
+/*
+ * PKCS#5 includes PBKDF2 and more
+ *
+ * http://tools.ietf.org/html/rfc2898 (Specification)
+ * http://tools.ietf.org/html/rfc6070 (Test vectors)
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_PKCS5_C)
+
+#include "mbedcrypto/pkcs5.h"
+
+#if defined(MBEDCRYPTO_ASN1_PARSE_C)
+#include "mbedcrypto/asn1.h"
+#include "mbedcrypto/cipher.h"
+#include "mbedcrypto/oid.h"
+#endif /* MBEDCRYPTO_ASN1_PARSE_C */
+
+#include <string.h>
+
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#include <stdio.h>
+#define mbedcrypto_printf printf
+#endif
+
+#if !defined(MBEDCRYPTO_ASN1_PARSE_C)
+int mbedcrypto_pkcs5_pbes2( const mbedcrypto_asn1_buf *pbe_params, int mode,
+ const unsigned char *pwd, size_t pwdlen,
+ const unsigned char *data, size_t datalen,
+ unsigned char *output )
+{
+ ((void) pbe_params);
+ ((void) mode);
+ ((void) pwd);
+ ((void) pwdlen);
+ ((void) data);
+ ((void) datalen);
+ ((void) output);
+ return( MBEDCRYPTO_ERR_PKCS5_FEATURE_UNAVAILABLE );
+}
+#else
+static int pkcs5_parse_pbkdf2_params( const mbedcrypto_asn1_buf *params,
+ mbedcrypto_asn1_buf *salt, int *iterations,
+ int *keylen, mbedcrypto_md_type_t *md_type )
+{
+ int ret;
+ mbedcrypto_asn1_buf prf_alg_oid;
+ unsigned char *p = params->p;
+ const unsigned char *end = params->p + params->len;
+
+ if( params->tag != ( MBEDCRYPTO_ASN1_CONSTRUCTED | MBEDCRYPTO_ASN1_SEQUENCE ) )
+ return( MBEDCRYPTO_ERR_PKCS5_INVALID_FORMAT +
+ MBEDCRYPTO_ERR_ASN1_UNEXPECTED_TAG );
+ /*
+ * PBKDF2-params ::= SEQUENCE {
+ * salt OCTET STRING,
+ * iterationCount INTEGER,
+ * keyLength INTEGER OPTIONAL
+ * prf AlgorithmIdentifier DEFAULT algid-hmacWithSHA1
+ * }
+ *
+ */
+ if( ( ret = mbedcrypto_asn1_get_tag( &p, end, &salt->len, MBEDCRYPTO_ASN1_OCTET_STRING ) ) != 0 )
+ return( MBEDCRYPTO_ERR_PKCS5_INVALID_FORMAT + ret );
+
+ salt->p = p;
+ p += salt->len;
+
+ if( ( ret = mbedcrypto_asn1_get_int( &p, end, iterations ) ) != 0 )
+ return( MBEDCRYPTO_ERR_PKCS5_INVALID_FORMAT + ret );
+
+ if( p == end )
+ return( 0 );
+
+ if( ( ret = mbedcrypto_asn1_get_int( &p, end, keylen ) ) != 0 )
+ {
+ if( ret != MBEDCRYPTO_ERR_ASN1_UNEXPECTED_TAG )
+ return( MBEDCRYPTO_ERR_PKCS5_INVALID_FORMAT + ret );
+ }
+
+ if( p == end )
+ return( 0 );
+
+ if( ( ret = mbedcrypto_asn1_get_alg_null( &p, end, &prf_alg_oid ) ) != 0 )
+ return( MBEDCRYPTO_ERR_PKCS5_INVALID_FORMAT + ret );
+
+ if( mbedcrypto_oid_get_md_hmac( &prf_alg_oid, md_type ) != 0 )
+ return( MBEDCRYPTO_ERR_PKCS5_FEATURE_UNAVAILABLE );
+
+ if( p != end )
+ return( MBEDCRYPTO_ERR_PKCS5_INVALID_FORMAT +
+ MBEDCRYPTO_ERR_ASN1_LENGTH_MISMATCH );
+
+ return( 0 );
+}
+
+int mbedcrypto_pkcs5_pbes2( const mbedcrypto_asn1_buf *pbe_params, int mode,
+ const unsigned char *pwd, size_t pwdlen,
+ const unsigned char *data, size_t datalen,
+ unsigned char *output )
+{
+ int ret, iterations = 0, keylen = 0;
+ unsigned char *p, *end;
+ mbedcrypto_asn1_buf kdf_alg_oid, enc_scheme_oid, kdf_alg_params, enc_scheme_params;
+ mbedcrypto_asn1_buf salt;
+ mbedcrypto_md_type_t md_type = MBEDCRYPTO_MD_SHA1;
+ unsigned char key[32], iv[32];
+ size_t olen = 0;
+ const mbedcrypto_md_info_t *md_info;
+ const mbedcrypto_cipher_info_t *cipher_info;
+ mbedcrypto_md_context_t md_ctx;
+ mbedcrypto_cipher_type_t cipher_alg;
+ mbedcrypto_cipher_context_t cipher_ctx;
+
+ p = pbe_params->p;
+ end = p + pbe_params->len;
+
+ /*
+ * PBES2-params ::= SEQUENCE {
+ * keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
+ * encryptionScheme AlgorithmIdentifier {{PBES2-Encs}}
+ * }
+ */
+ if( pbe_params->tag != ( MBEDCRYPTO_ASN1_CONSTRUCTED | MBEDCRYPTO_ASN1_SEQUENCE ) )
+ return( MBEDCRYPTO_ERR_PKCS5_INVALID_FORMAT +
+ MBEDCRYPTO_ERR_ASN1_UNEXPECTED_TAG );
+
+ if( ( ret = mbedcrypto_asn1_get_alg( &p, end, &kdf_alg_oid, &kdf_alg_params ) ) != 0 )
+ return( MBEDCRYPTO_ERR_PKCS5_INVALID_FORMAT + ret );
+
+ // Only PBKDF2 supported at the moment
+ //
+ if( MBEDCRYPTO_OID_CMP( MBEDCRYPTO_OID_PKCS5_PBKDF2, &kdf_alg_oid ) != 0 )
+ return( MBEDCRYPTO_ERR_PKCS5_FEATURE_UNAVAILABLE );
+
+ if( ( ret = pkcs5_parse_pbkdf2_params( &kdf_alg_params,
+ &salt, &iterations, &keylen,
+ &md_type ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ md_info = mbedcrypto_md_info_from_type( md_type );
+ if( md_info == NULL )
+ return( MBEDCRYPTO_ERR_PKCS5_FEATURE_UNAVAILABLE );
+
+ if( ( ret = mbedcrypto_asn1_get_alg( &p, end, &enc_scheme_oid,
+ &enc_scheme_params ) ) != 0 )
+ {
+ return( MBEDCRYPTO_ERR_PKCS5_INVALID_FORMAT + ret );
+ }
+
+ if( mbedcrypto_oid_get_cipher_alg( &enc_scheme_oid, &cipher_alg ) != 0 )
+ return( MBEDCRYPTO_ERR_PKCS5_FEATURE_UNAVAILABLE );
+
+ cipher_info = mbedcrypto_cipher_info_from_type( cipher_alg );
+ if( cipher_info == NULL )
+ return( MBEDCRYPTO_ERR_PKCS5_FEATURE_UNAVAILABLE );
+
+ /*
+ * The value of keylen from pkcs5_parse_pbkdf2_params() is ignored
+ * since it is optional and we don't know if it was set or not
+ */
+ keylen = cipher_info->key_bitlen / 8;
+
+ if( enc_scheme_params.tag != MBEDCRYPTO_ASN1_OCTET_STRING ||
+ enc_scheme_params.len != cipher_info->iv_size )
+ {
+ return( MBEDCRYPTO_ERR_PKCS5_INVALID_FORMAT );
+ }
+
+ mbedcrypto_md_init( &md_ctx );
+ mbedcrypto_cipher_init( &cipher_ctx );
+
+ memcpy( iv, enc_scheme_params.p, enc_scheme_params.len );
+
+ if( ( ret = mbedcrypto_md_setup( &md_ctx, md_info, 1 ) ) != 0 )
+ goto exit;
+
+ if( ( ret = mbedcrypto_pkcs5_pbkdf2_hmac( &md_ctx, pwd, pwdlen, salt.p, salt.len,
+ iterations, keylen, key ) ) != 0 )
+ {
+ goto exit;
+ }
+
+ if( ( ret = mbedcrypto_cipher_setup( &cipher_ctx, cipher_info ) ) != 0 )
+ goto exit;
+
+ if( ( ret = mbedcrypto_cipher_setkey( &cipher_ctx, key, 8 * keylen, (mbedcrypto_operation_t) mode ) ) != 0 )
+ goto exit;
+
+ if( ( ret = mbedcrypto_cipher_crypt( &cipher_ctx, iv, enc_scheme_params.len,
+ data, datalen, output, &olen ) ) != 0 )
+ ret = MBEDCRYPTO_ERR_PKCS5_PASSWORD_MISMATCH;
+
+exit:
+ mbedcrypto_md_free( &md_ctx );
+ mbedcrypto_cipher_free( &cipher_ctx );
+
+ return( ret );
+}
+#endif /* MBEDCRYPTO_ASN1_PARSE_C */
+
+int mbedcrypto_pkcs5_pbkdf2_hmac( mbedcrypto_md_context_t *ctx, const unsigned char *password,
+ size_t plen, const unsigned char *salt, size_t slen,
+ unsigned int iteration_count,
+ uint32_t key_length, unsigned char *output )
+{
+ int ret, j;
+ unsigned int i;
+ unsigned char md1[MBEDCRYPTO_MD_MAX_SIZE];
+ unsigned char work[MBEDCRYPTO_MD_MAX_SIZE];
+ unsigned char md_size = mbedcrypto_md_get_size( ctx->md_info );
+ size_t use_len;
+ unsigned char *out_p = output;
+ unsigned char counter[4];
+
+ memset( counter, 0, 4 );
+ counter[3] = 1;
+
+ if( iteration_count > 0xFFFFFFFF )
+ return( MBEDCRYPTO_ERR_PKCS5_BAD_INPUT_DATA );
+
+ while( key_length )
+ {
+ // U1 ends up in work
+ //
+ if( ( ret = mbedcrypto_md_hmac_starts( ctx, password, plen ) ) != 0 )
+ return( ret );
+
+ if( ( ret = mbedcrypto_md_hmac_update( ctx, salt, slen ) ) != 0 )
+ return( ret );
+
+ if( ( ret = mbedcrypto_md_hmac_update( ctx, counter, 4 ) ) != 0 )
+ return( ret );
+
+ if( ( ret = mbedcrypto_md_hmac_finish( ctx, work ) ) != 0 )
+ return( ret );
+
+ memcpy( md1, work, md_size );
+
+ for( i = 1; i < iteration_count; i++ )
+ {
+ // U2 ends up in md1
+ //
+ if( ( ret = mbedcrypto_md_hmac_starts( ctx, password, plen ) ) != 0 )
+ return( ret );
+
+ if( ( ret = mbedcrypto_md_hmac_update( ctx, md1, md_size ) ) != 0 )
+ return( ret );
+
+ if( ( ret = mbedcrypto_md_hmac_finish( ctx, md1 ) ) != 0 )
+ return( ret );
+
+ // U1 xor U2
+ //
+ for( j = 0; j < md_size; j++ )
+ work[j] ^= md1[j];
+ }
+
+ use_len = ( key_length < md_size ) ? key_length : md_size;
+ memcpy( out_p, work, use_len );
+
+ key_length -= (uint32_t) use_len;
+ out_p += use_len;
+
+ for( i = 4; i > 0; i-- )
+ if( ++counter[i - 1] != 0 )
+ break;
+ }
+
+ return( 0 );
+}
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+
+#if !defined(MBEDCRYPTO_SHA1_C)
+int mbedcrypto_pkcs5_self_test( int verbose )
+{
+ if( verbose != 0 )
+ mbedcrypto_printf( " PBKDF2 (SHA1): skipped\n\n" );
+
+ return( 0 );
+}
+#else
+
+#define MAX_TESTS 6
+
+static const size_t plen[MAX_TESTS] =
+ { 8, 8, 8, 24, 9 };
+
+static const unsigned char password[MAX_TESTS][32] =
+{
+ "password",
+ "password",
+ "password",
+ "passwordPASSWORDpassword",
+ "pass\0word",
+};
+
+static const size_t slen[MAX_TESTS] =
+ { 4, 4, 4, 36, 5 };
+
+static const unsigned char salt[MAX_TESTS][40] =
+{
+ "salt",
+ "salt",
+ "salt",
+ "saltSALTsaltSALTsaltSALTsaltSALTsalt",
+ "sa\0lt",
+};
+
+static const uint32_t it_cnt[MAX_TESTS] =
+ { 1, 2, 4096, 4096, 4096 };
+
+static const uint32_t key_len[MAX_TESTS] =
+ { 20, 20, 20, 25, 16 };
+
+static const unsigned char result_key[MAX_TESTS][32] =
+{
+ { 0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71,
+ 0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06,
+ 0x2f, 0xe0, 0x37, 0xa6 },
+ { 0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f, 0x8c,
+ 0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d, 0x41, 0xf0,
+ 0xd8, 0xde, 0x89, 0x57 },
+ { 0x4b, 0x00, 0x79, 0x01, 0xb7, 0x65, 0x48, 0x9a,
+ 0xbe, 0xad, 0x49, 0xd9, 0x26, 0xf7, 0x21, 0xd0,
+ 0x65, 0xa4, 0x29, 0xc1 },
+ { 0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, 0x9b,
+ 0x80, 0xc8, 0xd8, 0x36, 0x62, 0xc0, 0xe4, 0x4a,
+ 0x8b, 0x29, 0x1a, 0x96, 0x4c, 0xf2, 0xf0, 0x70,
+ 0x38 },
+ { 0x56, 0xfa, 0x6a, 0xa7, 0x55, 0x48, 0x09, 0x9d,
+ 0xcc, 0x37, 0xd7, 0xf0, 0x34, 0x25, 0xe0, 0xc3 },
+};
+
+int mbedcrypto_pkcs5_self_test( int verbose )
+{
+ mbedcrypto_md_context_t sha1_ctx;
+ const mbedcrypto_md_info_t *info_sha1;
+ int ret, i;
+ unsigned char key[64];
+
+ mbedcrypto_md_init( &sha1_ctx );
+
+ info_sha1 = mbedcrypto_md_info_from_type( MBEDCRYPTO_MD_SHA1 );
+ if( info_sha1 == NULL )
+ {
+ ret = 1;
+ goto exit;
+ }
+
+ if( ( ret = mbedcrypto_md_setup( &sha1_ctx, info_sha1, 1 ) ) != 0 )
+ {
+ ret = 1;
+ goto exit;
+ }
+
+ for( i = 0; i < MAX_TESTS; i++ )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( " PBKDF2 (SHA1) #%d: ", i );
+
+ ret = mbedcrypto_pkcs5_pbkdf2_hmac( &sha1_ctx, password[i], plen[i], salt[i],
+ slen[i], it_cnt[i], key_len[i], key );
+ if( ret != 0 ||
+ memcmp( result_key[i], key, key_len[i] ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+
+ ret = 1;
+ goto exit;
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "\n" );
+
+exit:
+ mbedcrypto_md_free( &sha1_ctx );
+
+ return( ret );
+}
+#endif /* MBEDCRYPTO_SHA1_C */
+
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#endif /* MBEDCRYPTO_PKCS5_C */
diff --git a/library/pkparse.c b/library/pkparse.c
new file mode 100644
index 0000000..76d83ab
--- /dev/null
+++ b/library/pkparse.c
@@ -0,0 +1,1448 @@
+/*
+ * Public Key layer for parsing key files and structures
+ *
+ * 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 Crypto (https://tls.mbed.org)
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_PK_PARSE_C)
+
+#include "mbedcrypto/pk.h"
+#include "mbedcrypto/asn1.h"
+#include "mbedcrypto/oid.h"
+#include "mbedcrypto/platform_util.h"
+
+#include <string.h>
+
+#if defined(MBEDCRYPTO_RSA_C)
+#include "mbedcrypto/rsa.h"
+#endif
+#if defined(MBEDCRYPTO_ECP_C)
+#include "mbedcrypto/ecp.h"
+#endif
+#if defined(MBEDCRYPTO_ECDSA_C)
+#include "mbedcrypto/ecdsa.h"
+#endif
+#if defined(MBEDCRYPTO_PEM_PARSE_C)
+#include "mbedcrypto/pem.h"
+#endif
+#if defined(MBEDCRYPTO_PKCS5_C)
+#include "mbedcrypto/pkcs5.h"
+#endif
+#if defined(MBEDCRYPTO_PKCS12_C)
+#include "mbedcrypto/pkcs12.h"
+#endif
+
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#include <stdlib.h>
+#define mbedcrypto_calloc calloc
+#define mbedcrypto_free free
+#endif
+
+#if defined(MBEDCRYPTO_FS_IO)
+/*
+ * Load all data from a file into a given buffer.
+ *
+ * The file is expected to contain either PEM or DER encoded data.
+ * A terminating null byte is always appended. It is included in the announced
+ * length only if the data looks like it is PEM encoded.
+ */
+int mbedcrypto_pk_load_file( const char *path, unsigned char **buf, size_t *n )
+{
+ FILE *f;
+ long size;
+
+ if( ( f = fopen( path, "rb" ) ) == NULL )
+ return( MBEDCRYPTO_ERR_PK_FILE_IO_ERROR );
+
+ fseek( f, 0, SEEK_END );
+ if( ( size = ftell( f ) ) == -1 )
+ {
+ fclose( f );
+ return( MBEDCRYPTO_ERR_PK_FILE_IO_ERROR );
+ }
+ fseek( f, 0, SEEK_SET );
+
+ *n = (size_t) size;
+
+ if( *n + 1 == 0 ||
+ ( *buf = mbedcrypto_calloc( 1, *n + 1 ) ) == NULL )
+ {
+ fclose( f );
+ return( MBEDCRYPTO_ERR_PK_ALLOC_FAILED );
+ }
+
+ if( fread( *buf, 1, *n, f ) != *n )
+ {
+ fclose( f );
+
+ mbedcrypto_platform_zeroize( *buf, *n );
+ mbedcrypto_free( *buf );
+
+ return( MBEDCRYPTO_ERR_PK_FILE_IO_ERROR );
+ }
+
+ fclose( f );
+
+ (*buf)[*n] = '\0';
+
+ if( strstr( (const char *) *buf, "-----BEGIN " ) != NULL )
+ ++*n;
+
+ return( 0 );
+}
+
+/*
+ * Load and parse a private key
+ */
+int mbedcrypto_pk_parse_keyfile( mbedcrypto_pk_context *ctx,
+ const char *path, const char *pwd )
+{
+ int ret;
+ size_t n;
+ unsigned char *buf;
+
+ if( ( ret = mbedcrypto_pk_load_file( path, &buf, &n ) ) != 0 )
+ return( ret );
+
+ if( pwd == NULL )
+ ret = mbedcrypto_pk_parse_key( ctx, buf, n, NULL, 0 );
+ else
+ ret = mbedcrypto_pk_parse_key( ctx, buf, n,
+ (const unsigned char *) pwd, strlen( pwd ) );
+
+ mbedcrypto_platform_zeroize( buf, n );
+ mbedcrypto_free( buf );
+
+ return( ret );
+}
+
+/*
+ * Load and parse a public key
+ */
+int mbedcrypto_pk_parse_public_keyfile( mbedcrypto_pk_context *ctx, const char *path )
+{
+ int ret;
+ size_t n;
+ unsigned char *buf;
+
+ if( ( ret = mbedcrypto_pk_load_file( path, &buf, &n ) ) != 0 )
+ return( ret );
+
+ ret = mbedcrypto_pk_parse_public_key( ctx, buf, n );
+
+ mbedcrypto_platform_zeroize( buf, n );
+ mbedcrypto_free( buf );
+
+ return( ret );
+}
+#endif /* MBEDCRYPTO_FS_IO */
+
+#if defined(MBEDCRYPTO_ECP_C)
+/* Minimally parse an ECParameters buffer to and mbedcrypto_asn1_buf
+ *
+ * ECParameters ::= CHOICE {
+ * namedCurve OBJECT IDENTIFIER
+ * specifiedCurve SpecifiedECDomain -- = SEQUENCE { ... }
+ * -- implicitCurve NULL
+ * }
+ */
+static int pk_get_ecparams( unsigned char **p, const unsigned char *end,
+ mbedcrypto_asn1_buf *params )
+{
+ int ret;
+
+ if ( end - *p < 1 )
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT +
+ MBEDCRYPTO_ERR_ASN1_OUT_OF_DATA );
+
+ /* Tag may be either OID or SEQUENCE */
+ params->tag = **p;
+ if( params->tag != MBEDCRYPTO_ASN1_OID
+#if defined(MBEDCRYPTO_PK_PARSE_EC_EXTENDED)
+ && params->tag != ( MBEDCRYPTO_ASN1_CONSTRUCTED | MBEDCRYPTO_ASN1_SEQUENCE )
+#endif
+ )
+ {
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT +
+ MBEDCRYPTO_ERR_ASN1_UNEXPECTED_TAG );
+ }
+
+ if( ( ret = mbedcrypto_asn1_get_tag( p, end, ¶ms->len, params->tag ) ) != 0 )
+ {
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT + ret );
+ }
+
+ params->p = *p;
+ *p += params->len;
+
+ if( *p != end )
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT +
+ MBEDCRYPTO_ERR_ASN1_LENGTH_MISMATCH );
+
+ return( 0 );
+}
+
+#if defined(MBEDCRYPTO_PK_PARSE_EC_EXTENDED)
+/*
+ * Parse a SpecifiedECDomain (SEC 1 C.2) and (mostly) fill the group with it.
+ * WARNING: the resulting group should only be used with
+ * pk_group_id_from_specified(), since its base point may not be set correctly
+ * if it was encoded compressed.
+ *
+ * SpecifiedECDomain ::= SEQUENCE {
+ * version SpecifiedECDomainVersion(ecdpVer1 | ecdpVer2 | ecdpVer3, ...),
+ * fieldID FieldID {{FieldTypes}},
+ * curve Curve,
+ * base ECPoint,
+ * order INTEGER,
+ * cofactor INTEGER OPTIONAL,
+ * hash HashAlgorithm OPTIONAL,
+ * ...
+ * }
+ *
+ * We only support prime-field as field type, and ignore hash and cofactor.
+ */
+static int pk_group_from_specified( const mbedcrypto_asn1_buf *params, mbedcrypto_ecp_group *grp )
+{
+ int ret;
+ unsigned char *p = params->p;
+ const unsigned char * const end = params->p + params->len;
+ const unsigned char *end_field, *end_curve;
+ size_t len;
+ int ver;
+
+ /* SpecifiedECDomainVersion ::= INTEGER { 1, 2, 3 } */
+ if( ( ret = mbedcrypto_asn1_get_int( &p, end, &ver ) ) != 0 )
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT + ret );
+
+ if( ver < 1 || ver > 3 )
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT );
+
+ /*
+ * FieldID { FIELD-ID:IOSet } ::= SEQUENCE { -- Finite field
+ * fieldType FIELD-ID.&id({IOSet}),
+ * parameters FIELD-ID.&Type({IOSet}{@fieldType})
+ * }
+ */
+ if( ( ret = mbedcrypto_asn1_get_tag( &p, end, &len,
+ MBEDCRYPTO_ASN1_CONSTRUCTED | MBEDCRYPTO_ASN1_SEQUENCE ) ) != 0 )
+ return( ret );
+
+ end_field = p + len;
+
+ /*
+ * FIELD-ID ::= TYPE-IDENTIFIER
+ * FieldTypes FIELD-ID ::= {
+ * { Prime-p IDENTIFIED BY prime-field } |
+ * { Characteristic-two IDENTIFIED BY characteristic-two-field }
+ * }
+ * prime-field OBJECT IDENTIFIER ::= { id-fieldType 1 }
+ */
+ if( ( ret = mbedcrypto_asn1_get_tag( &p, end_field, &len, MBEDCRYPTO_ASN1_OID ) ) != 0 )
+ return( ret );
+
+ if( len != MBEDCRYPTO_OID_SIZE( MBEDCRYPTO_OID_ANSI_X9_62_PRIME_FIELD ) ||
+ memcmp( p, MBEDCRYPTO_OID_ANSI_X9_62_PRIME_FIELD, len ) != 0 )
+ {
+ return( MBEDCRYPTO_ERR_PK_FEATURE_UNAVAILABLE );
+ }
+
+ p += len;
+
+ /* Prime-p ::= INTEGER -- Field of size p. */
+ if( ( ret = mbedcrypto_asn1_get_mpi( &p, end_field, &grp->P ) ) != 0 )
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT + ret );
+
+ grp->pbits = mbedcrypto_mpi_bitlen( &grp->P );
+
+ if( p != end_field )
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT +
+ MBEDCRYPTO_ERR_ASN1_LENGTH_MISMATCH );
+
+ /*
+ * Curve ::= SEQUENCE {
+ * a FieldElement,
+ * b FieldElement,
+ * seed BIT STRING OPTIONAL
+ * -- Shall be present if used in SpecifiedECDomain
+ * -- with version equal to ecdpVer2 or ecdpVer3
+ * }
+ */
+ if( ( ret = mbedcrypto_asn1_get_tag( &p, end, &len,
+ MBEDCRYPTO_ASN1_CONSTRUCTED | MBEDCRYPTO_ASN1_SEQUENCE ) ) != 0 )
+ return( ret );
+
+ end_curve = p + len;
+
+ /*
+ * FieldElement ::= OCTET STRING
+ * containing an integer in the case of a prime field
+ */
+ if( ( ret = mbedcrypto_asn1_get_tag( &p, end_curve, &len, MBEDCRYPTO_ASN1_OCTET_STRING ) ) != 0 ||
+ ( ret = mbedcrypto_mpi_read_binary( &grp->A, p, len ) ) != 0 )
+ {
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT + ret );
+ }
+
+ p += len;
+
+ if( ( ret = mbedcrypto_asn1_get_tag( &p, end_curve, &len, MBEDCRYPTO_ASN1_OCTET_STRING ) ) != 0 ||
+ ( ret = mbedcrypto_mpi_read_binary( &grp->B, p, len ) ) != 0 )
+ {
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT + ret );
+ }
+
+ p += len;
+
+ /* Ignore seed BIT STRING OPTIONAL */
+ if( ( ret = mbedcrypto_asn1_get_tag( &p, end_curve, &len, MBEDCRYPTO_ASN1_BIT_STRING ) ) == 0 )
+ p += len;
+
+ if( p != end_curve )
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT +
+ MBEDCRYPTO_ERR_ASN1_LENGTH_MISMATCH );
+
+ /*
+ * ECPoint ::= OCTET STRING
+ */
+ if( ( ret = mbedcrypto_asn1_get_tag( &p, end, &len, MBEDCRYPTO_ASN1_OCTET_STRING ) ) != 0 )
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT + ret );
+
+ if( ( ret = mbedcrypto_ecp_point_read_binary( grp, &grp->G,
+ ( const unsigned char *) p, len ) ) != 0 )
+ {
+ /*
+ * If we can't read the point because it's compressed, cheat by
+ * reading only the X coordinate and the parity bit of Y.
+ */
+ if( ret != MBEDCRYPTO_ERR_ECP_FEATURE_UNAVAILABLE ||
+ ( p[0] != 0x02 && p[0] != 0x03 ) ||
+ len != mbedcrypto_mpi_size( &grp->P ) + 1 ||
+ mbedcrypto_mpi_read_binary( &grp->G.X, p + 1, len - 1 ) != 0 ||
+ mbedcrypto_mpi_lset( &grp->G.Y, p[0] - 2 ) != 0 ||
+ mbedcrypto_mpi_lset( &grp->G.Z, 1 ) != 0 )
+ {
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT );
+ }
+ }
+
+ p += len;
+
+ /*
+ * order INTEGER
+ */
+ if( ( ret = mbedcrypto_asn1_get_mpi( &p, end, &grp->N ) ) != 0 )
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT + ret );
+
+ grp->nbits = mbedcrypto_mpi_bitlen( &grp->N );
+
+ /*
+ * Allow optional elements by purposefully not enforcing p == end here.
+ */
+
+ return( 0 );
+}
+
+/*
+ * Find the group id associated with an (almost filled) group as generated by
+ * pk_group_from_specified(), or return an error if unknown.
+ */
+static int pk_group_id_from_group( const mbedcrypto_ecp_group *grp, mbedcrypto_ecp_group_id *grp_id )
+{
+ int ret = 0;
+ mbedcrypto_ecp_group ref;
+ const mbedcrypto_ecp_group_id *id;
+
+ mbedcrypto_ecp_group_init( &ref );
+
+ for( id = mbedcrypto_ecp_grp_id_list(); *id != MBEDCRYPTO_ECP_DP_NONE; id++ )
+ {
+ /* Load the group associated to that id */
+ mbedcrypto_ecp_group_free( &ref );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_ecp_group_load( &ref, *id ) );
+
+ /* Compare to the group we were given, starting with easy tests */
+ if( grp->pbits == ref.pbits && grp->nbits == ref.nbits &&
+ mbedcrypto_mpi_cmp_mpi( &grp->P, &ref.P ) == 0 &&
+ mbedcrypto_mpi_cmp_mpi( &grp->A, &ref.A ) == 0 &&
+ mbedcrypto_mpi_cmp_mpi( &grp->B, &ref.B ) == 0 &&
+ mbedcrypto_mpi_cmp_mpi( &grp->N, &ref.N ) == 0 &&
+ mbedcrypto_mpi_cmp_mpi( &grp->G.X, &ref.G.X ) == 0 &&
+ mbedcrypto_mpi_cmp_mpi( &grp->G.Z, &ref.G.Z ) == 0 &&
+ /* For Y we may only know the parity bit, so compare only that */
+ mbedcrypto_mpi_get_bit( &grp->G.Y, 0 ) == mbedcrypto_mpi_get_bit( &ref.G.Y, 0 ) )
+ {
+ break;
+ }
+
+ }
+
+cleanup:
+ mbedcrypto_ecp_group_free( &ref );
+
+ *grp_id = *id;
+
+ if( ret == 0 && *id == MBEDCRYPTO_ECP_DP_NONE )
+ ret = MBEDCRYPTO_ERR_ECP_FEATURE_UNAVAILABLE;
+
+ return( ret );
+}
+
+/*
+ * Parse a SpecifiedECDomain (SEC 1 C.2) and find the associated group ID
+ */
+static int pk_group_id_from_specified( const mbedcrypto_asn1_buf *params,
+ mbedcrypto_ecp_group_id *grp_id )
+{
+ int ret;
+ mbedcrypto_ecp_group grp;
+
+ mbedcrypto_ecp_group_init( &grp );
+
+ if( ( ret = pk_group_from_specified( params, &grp ) ) != 0 )
+ goto cleanup;
+
+ ret = pk_group_id_from_group( &grp, grp_id );
+
+cleanup:
+ mbedcrypto_ecp_group_free( &grp );
+
+ return( ret );
+}
+#endif /* MBEDCRYPTO_PK_PARSE_EC_EXTENDED */
+
+/*
+ * Use EC parameters to initialise an EC group
+ *
+ * ECParameters ::= CHOICE {
+ * namedCurve OBJECT IDENTIFIER
+ * specifiedCurve SpecifiedECDomain -- = SEQUENCE { ... }
+ * -- implicitCurve NULL
+ */
+static int pk_use_ecparams( const mbedcrypto_asn1_buf *params, mbedcrypto_ecp_group *grp )
+{
+ int ret;
+ mbedcrypto_ecp_group_id grp_id;
+
+ if( params->tag == MBEDCRYPTO_ASN1_OID )
+ {
+ if( mbedcrypto_oid_get_ec_grp( params, &grp_id ) != 0 )
+ return( MBEDCRYPTO_ERR_PK_UNKNOWN_NAMED_CURVE );
+ }
+ else
+ {
+#if defined(MBEDCRYPTO_PK_PARSE_EC_EXTENDED)
+ if( ( ret = pk_group_id_from_specified( params, &grp_id ) ) != 0 )
+ return( ret );
+#else
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT );
+#endif
+ }
+
+ /*
+ * grp may already be initilialized; if so, make sure IDs match
+ */
+ if( grp->id != MBEDCRYPTO_ECP_DP_NONE && grp->id != grp_id )
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT );
+
+ if( ( ret = mbedcrypto_ecp_group_load( grp, grp_id ) ) != 0 )
+ return( ret );
+
+ return( 0 );
+}
+
+/*
+ * EC public key is an EC point
+ *
+ * The caller is responsible for clearing the structure upon failure if
+ * desired. Take care to pass along the possible ECP_FEATURE_UNAVAILABLE
+ * return code of mbedcrypto_ecp_point_read_binary() and leave p in a usable state.
+ */
+static int pk_get_ecpubkey( unsigned char **p, const unsigned char *end,
+ mbedcrypto_ecp_keypair *key )
+{
+ int ret;
+
+ if( ( ret = mbedcrypto_ecp_point_read_binary( &key->grp, &key->Q,
+ (const unsigned char *) *p, end - *p ) ) == 0 )
+ {
+ ret = mbedcrypto_ecp_check_pubkey( &key->grp, &key->Q );
+ }
+
+ /*
+ * We know mbedcrypto_ecp_point_read_binary consumed all bytes or failed
+ */
+ *p = (unsigned char *) end;
+
+ return( ret );
+}
+#endif /* MBEDCRYPTO_ECP_C */
+
+#if defined(MBEDCRYPTO_RSA_C)
+/*
+ * RSAPublicKey ::= SEQUENCE {
+ * modulus INTEGER, -- n
+ * publicExponent INTEGER -- e
+ * }
+ */
+static int pk_get_rsapubkey( unsigned char **p,
+ const unsigned char *end,
+ mbedcrypto_rsa_context *rsa )
+{
+ int ret;
+ size_t len;
+
+ if( ( ret = mbedcrypto_asn1_get_tag( p, end, &len,
+ MBEDCRYPTO_ASN1_CONSTRUCTED | MBEDCRYPTO_ASN1_SEQUENCE ) ) != 0 )
+ return( MBEDCRYPTO_ERR_PK_INVALID_PUBKEY + ret );
+
+ if( *p + len != end )
+ return( MBEDCRYPTO_ERR_PK_INVALID_PUBKEY +
+ MBEDCRYPTO_ERR_ASN1_LENGTH_MISMATCH );
+
+ /* Import N */
+ if( ( ret = mbedcrypto_asn1_get_tag( p, end, &len, MBEDCRYPTO_ASN1_INTEGER ) ) != 0 )
+ return( MBEDCRYPTO_ERR_PK_INVALID_PUBKEY + ret );
+
+ if( ( ret = mbedcrypto_rsa_import_raw( rsa, *p, len, NULL, 0, NULL, 0,
+ NULL, 0, NULL, 0 ) ) != 0 )
+ return( MBEDCRYPTO_ERR_PK_INVALID_PUBKEY );
+
+ *p += len;
+
+ /* Import E */
+ if( ( ret = mbedcrypto_asn1_get_tag( p, end, &len, MBEDCRYPTO_ASN1_INTEGER ) ) != 0 )
+ return( MBEDCRYPTO_ERR_PK_INVALID_PUBKEY + ret );
+
+ if( ( ret = mbedcrypto_rsa_import_raw( rsa, NULL, 0, NULL, 0, NULL, 0,
+ NULL, 0, *p, len ) ) != 0 )
+ return( MBEDCRYPTO_ERR_PK_INVALID_PUBKEY );
+
+ *p += len;
+
+ if( mbedcrypto_rsa_complete( rsa ) != 0 ||
+ mbedcrypto_rsa_check_pubkey( rsa ) != 0 )
+ {
+ return( MBEDCRYPTO_ERR_PK_INVALID_PUBKEY );
+ }
+
+ if( *p != end )
+ return( MBEDCRYPTO_ERR_PK_INVALID_PUBKEY +
+ MBEDCRYPTO_ERR_ASN1_LENGTH_MISMATCH );
+
+ return( 0 );
+}
+#endif /* MBEDCRYPTO_RSA_C */
+
+/* Get a PK algorithm identifier
+ *
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL }
+ */
+static int pk_get_pk_alg( unsigned char **p,
+ const unsigned char *end,
+ mbedcrypto_pk_type_t *pk_alg, mbedcrypto_asn1_buf *params )
+{
+ int ret;
+ mbedcrypto_asn1_buf alg_oid;
+
+ memset( params, 0, sizeof(mbedcrypto_asn1_buf) );
+
+ if( ( ret = mbedcrypto_asn1_get_alg( p, end, &alg_oid, params ) ) != 0 )
+ return( MBEDCRYPTO_ERR_PK_INVALID_ALG + ret );
+
+ if( mbedcrypto_oid_get_pk_alg( &alg_oid, pk_alg ) != 0 )
+ return( MBEDCRYPTO_ERR_PK_UNKNOWN_PK_ALG );
+
+ /*
+ * No parameters with RSA (only for EC)
+ */
+ if( *pk_alg == MBEDCRYPTO_PK_RSA &&
+ ( ( params->tag != MBEDCRYPTO_ASN1_NULL && params->tag != 0 ) ||
+ params->len != 0 ) )
+ {
+ return( MBEDCRYPTO_ERR_PK_INVALID_ALG );
+ }
+
+ return( 0 );
+}
+
+/*
+ * SubjectPublicKeyInfo ::= SEQUENCE {
+ * algorithm AlgorithmIdentifier,
+ * subjectPublicKey BIT STRING }
+ */
+int mbedcrypto_pk_parse_subpubkey( unsigned char **p, const unsigned char *end,
+ mbedcrypto_pk_context *pk )
+{
+ int ret;
+ size_t len;
+ mbedcrypto_asn1_buf alg_params;
+ mbedcrypto_pk_type_t pk_alg = MBEDCRYPTO_PK_NONE;
+ const mbedcrypto_pk_info_t *pk_info;
+
+ if( ( ret = mbedcrypto_asn1_get_tag( p, end, &len,
+ MBEDCRYPTO_ASN1_CONSTRUCTED | MBEDCRYPTO_ASN1_SEQUENCE ) ) != 0 )
+ {
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT + ret );
+ }
+
+ end = *p + len;
+
+ if( ( ret = pk_get_pk_alg( p, end, &pk_alg, &alg_params ) ) != 0 )
+ return( ret );
+
+ if( ( ret = mbedcrypto_asn1_get_bitstring_null( p, end, &len ) ) != 0 )
+ return( MBEDCRYPTO_ERR_PK_INVALID_PUBKEY + ret );
+
+ if( *p + len != end )
+ return( MBEDCRYPTO_ERR_PK_INVALID_PUBKEY +
+ MBEDCRYPTO_ERR_ASN1_LENGTH_MISMATCH );
+
+ if( ( pk_info = mbedcrypto_pk_info_from_type( pk_alg ) ) == NULL )
+ return( MBEDCRYPTO_ERR_PK_UNKNOWN_PK_ALG );
+
+ if( ( ret = mbedcrypto_pk_setup( pk, pk_info ) ) != 0 )
+ return( ret );
+
+#if defined(MBEDCRYPTO_RSA_C)
+ if( pk_alg == MBEDCRYPTO_PK_RSA )
+ {
+ ret = pk_get_rsapubkey( p, end, mbedcrypto_pk_rsa( *pk ) );
+ } else
+#endif /* MBEDCRYPTO_RSA_C */
+#if defined(MBEDCRYPTO_ECP_C)
+ if( pk_alg == MBEDCRYPTO_PK_ECKEY_DH || pk_alg == MBEDCRYPTO_PK_ECKEY )
+ {
+ ret = pk_use_ecparams( &alg_params, &mbedcrypto_pk_ec( *pk )->grp );
+ if( ret == 0 )
+ ret = pk_get_ecpubkey( p, end, mbedcrypto_pk_ec( *pk ) );
+ } else
+#endif /* MBEDCRYPTO_ECP_C */
+ ret = MBEDCRYPTO_ERR_PK_UNKNOWN_PK_ALG;
+
+ if( ret == 0 && *p != end )
+ ret = MBEDCRYPTO_ERR_PK_INVALID_PUBKEY
+ MBEDCRYPTO_ERR_ASN1_LENGTH_MISMATCH;
+
+ if( ret != 0 )
+ mbedcrypto_pk_free( pk );
+
+ return( ret );
+}
+
+#if defined(MBEDCRYPTO_RSA_C)
+/*
+ * Parse a PKCS#1 encoded private RSA key
+ */
+static int pk_parse_key_pkcs1_der( mbedcrypto_rsa_context *rsa,
+ const unsigned char *key,
+ size_t keylen )
+{
+ int ret, version;
+ size_t len;
+ unsigned char *p, *end;
+
+ mbedcrypto_mpi T;
+ mbedcrypto_mpi_init( &T );
+
+ p = (unsigned char *) key;
+ end = p + keylen;
+
+ /*
+ * This function parses the RSAPrivateKey (PKCS#1)
+ *
+ * RSAPrivateKey ::= SEQUENCE {
+ * version Version,
+ * modulus INTEGER, -- n
+ * publicExponent INTEGER, -- e
+ * privateExponent INTEGER, -- d
+ * prime1 INTEGER, -- p
+ * prime2 INTEGER, -- q
+ * exponent1 INTEGER, -- d mod (p-1)
+ * exponent2 INTEGER, -- d mod (q-1)
+ * coefficient INTEGER, -- (inverse of q) mod p
+ * otherPrimeInfos OtherPrimeInfos OPTIONAL
+ * }
+ */
+ if( ( ret = mbedcrypto_asn1_get_tag( &p, end, &len,
+ MBEDCRYPTO_ASN1_CONSTRUCTED | MBEDCRYPTO_ASN1_SEQUENCE ) ) != 0 )
+ {
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT + ret );
+ }
+
+ end = p + len;
+
+ if( ( ret = mbedcrypto_asn1_get_int( &p, end, &version ) ) != 0 )
+ {
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT + ret );
+ }
+
+ if( version != 0 )
+ {
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_VERSION );
+ }
+
+ /* Import N */
+ if( ( ret = mbedcrypto_asn1_get_tag( &p, end, &len,
+ MBEDCRYPTO_ASN1_INTEGER ) ) != 0 ||
+ ( ret = mbedcrypto_rsa_import_raw( rsa, p, len, NULL, 0, NULL, 0,
+ NULL, 0, NULL, 0 ) ) != 0 )
+ goto cleanup;
+ p += len;
+
+ /* Import E */
+ if( ( ret = mbedcrypto_asn1_get_tag( &p, end, &len,
+ MBEDCRYPTO_ASN1_INTEGER ) ) != 0 ||
+ ( ret = mbedcrypto_rsa_import_raw( rsa, NULL, 0, NULL, 0, NULL, 0,
+ NULL, 0, p, len ) ) != 0 )
+ goto cleanup;
+ p += len;
+
+ /* Import D */
+ if( ( ret = mbedcrypto_asn1_get_tag( &p, end, &len,
+ MBEDCRYPTO_ASN1_INTEGER ) ) != 0 ||
+ ( ret = mbedcrypto_rsa_import_raw( rsa, NULL, 0, NULL, 0, NULL, 0,
+ p, len, NULL, 0 ) ) != 0 )
+ goto cleanup;
+ p += len;
+
+ /* Import P */
+ if( ( ret = mbedcrypto_asn1_get_tag( &p, end, &len,
+ MBEDCRYPTO_ASN1_INTEGER ) ) != 0 ||
+ ( ret = mbedcrypto_rsa_import_raw( rsa, NULL, 0, p, len, NULL, 0,
+ NULL, 0, NULL, 0 ) ) != 0 )
+ goto cleanup;
+ p += len;
+
+ /* Import Q */
+ if( ( ret = mbedcrypto_asn1_get_tag( &p, end, &len,
+ MBEDCRYPTO_ASN1_INTEGER ) ) != 0 ||
+ ( ret = mbedcrypto_rsa_import_raw( rsa, NULL, 0, NULL, 0, p, len,
+ NULL, 0, NULL, 0 ) ) != 0 )
+ goto cleanup;
+ p += len;
+
+ /* Complete the RSA private key */
+ if( ( ret = mbedcrypto_rsa_complete( rsa ) ) != 0 )
+ goto cleanup;
+
+ /* Check optional parameters */
+ if( ( ret = mbedcrypto_asn1_get_mpi( &p, end, &T ) ) != 0 ||
+ ( ret = mbedcrypto_asn1_get_mpi( &p, end, &T ) ) != 0 ||
+ ( ret = mbedcrypto_asn1_get_mpi( &p, end, &T ) ) != 0 )
+ goto cleanup;
+
+ if( p != end )
+ {
+ ret = MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT +
+ MBEDCRYPTO_ERR_ASN1_LENGTH_MISMATCH ;
+ }
+
+cleanup:
+
+ mbedcrypto_mpi_free( &T );
+
+ if( ret != 0 )
+ {
+ /* Wrap error code if it's coming from a lower level */
+ if( ( ret & 0xff80 ) == 0 )
+ ret = MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT + ret;
+ else
+ ret = MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT;
+
+ mbedcrypto_rsa_free( rsa );
+ }
+
+ return( ret );
+}
+#endif /* MBEDCRYPTO_RSA_C */
+
+#if defined(MBEDCRYPTO_ECP_C)
+/*
+ * Parse a SEC1 encoded private EC key
+ */
+static int pk_parse_key_sec1_der( mbedcrypto_ecp_keypair *eck,
+ const unsigned char *key,
+ size_t keylen )
+{
+ int ret;
+ int version, pubkey_done;
+ size_t len;
+ mbedcrypto_asn1_buf params;
+ unsigned char *p = (unsigned char *) key;
+ unsigned char *end = p + keylen;
+ unsigned char *end2;
+
+ /*
+ * RFC 5915, or SEC1 Appendix C.4
+ *
+ * ECPrivateKey ::= SEQUENCE {
+ * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
+ * privateKey OCTET STRING,
+ * parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
+ * publicKey [1] BIT STRING OPTIONAL
+ * }
+ */
+ if( ( ret = mbedcrypto_asn1_get_tag( &p, end, &len,
+ MBEDCRYPTO_ASN1_CONSTRUCTED | MBEDCRYPTO_ASN1_SEQUENCE ) ) != 0 )
+ {
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT + ret );
+ }
+
+ end = p + len;
+
+ if( ( ret = mbedcrypto_asn1_get_int( &p, end, &version ) ) != 0 )
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT + ret );
+
+ if( version != 1 )
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_VERSION );
+
+ if( ( ret = mbedcrypto_asn1_get_tag( &p, end, &len, MBEDCRYPTO_ASN1_OCTET_STRING ) ) != 0 )
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT + ret );
+
+ if( ( ret = mbedcrypto_mpi_read_binary( &eck->d, p, len ) ) != 0 )
+ {
+ mbedcrypto_ecp_keypair_free( eck );
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT + ret );
+ }
+
+ p += len;
+
+ pubkey_done = 0;
+ if( p != end )
+ {
+ /*
+ * Is 'parameters' present?
+ */
+ if( ( ret = mbedcrypto_asn1_get_tag( &p, end, &len,
+ MBEDCRYPTO_ASN1_CONTEXT_SPECIFIC | MBEDCRYPTO_ASN1_CONSTRUCTED | 0 ) ) == 0 )
+ {
+ if( ( ret = pk_get_ecparams( &p, p + len, ¶ms) ) != 0 ||
+ ( ret = pk_use_ecparams( ¶ms, &eck->grp ) ) != 0 )
+ {
+ mbedcrypto_ecp_keypair_free( eck );
+ return( ret );
+ }
+ }
+ else if( ret != MBEDCRYPTO_ERR_ASN1_UNEXPECTED_TAG )
+ {
+ mbedcrypto_ecp_keypair_free( eck );
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT + ret );
+ }
+ }
+
+ if( p != end )
+ {
+ /*
+ * Is 'publickey' present? If not, or if we can't read it (eg because it
+ * is compressed), create it from the private key.
+ */
+ if( ( ret = mbedcrypto_asn1_get_tag( &p, end, &len,
+ MBEDCRYPTO_ASN1_CONTEXT_SPECIFIC | MBEDCRYPTO_ASN1_CONSTRUCTED | 1 ) ) == 0 )
+ {
+ end2 = p + len;
+
+ if( ( ret = mbedcrypto_asn1_get_bitstring_null( &p, end2, &len ) ) != 0 )
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT + ret );
+
+ if( p + len != end2 )
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT +
+ MBEDCRYPTO_ERR_ASN1_LENGTH_MISMATCH );
+
+ if( ( ret = pk_get_ecpubkey( &p, end2, eck ) ) == 0 )
+ pubkey_done = 1;
+ else
+ {
+ /*
+ * The only acceptable failure mode of pk_get_ecpubkey() above
+ * is if the point format is not recognized.
+ */
+ if( ret != MBEDCRYPTO_ERR_ECP_FEATURE_UNAVAILABLE )
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT );
+ }
+ }
+ else if( ret != MBEDCRYPTO_ERR_ASN1_UNEXPECTED_TAG )
+ {
+ mbedcrypto_ecp_keypair_free( eck );
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT + ret );
+ }
+ }
+
+ if( ! pubkey_done &&
+ ( ret = mbedcrypto_ecp_mul( &eck->grp, &eck->Q, &eck->d, &eck->grp.G,
+ NULL, NULL ) ) != 0 )
+ {
+ mbedcrypto_ecp_keypair_free( eck );
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT + ret );
+ }
+
+ if( ( ret = mbedcrypto_ecp_check_privkey( &eck->grp, &eck->d ) ) != 0 )
+ {
+ mbedcrypto_ecp_keypair_free( eck );
+ return( ret );
+ }
+
+ return( 0 );
+}
+#endif /* MBEDCRYPTO_ECP_C */
+
+/*
+ * Parse an unencrypted PKCS#8 encoded private key
+ *
+ * Notes:
+ *
+ * - This function does not own the key buffer. It is the
+ * responsibility of the caller to take care of zeroizing
+ * and freeing it after use.
+ *
+ * - The function is responsible for freeing the provided
+ * PK context on failure.
+ *
+ */
+static int pk_parse_key_pkcs8_unencrypted_der(
+ mbedcrypto_pk_context *pk,
+ const unsigned char* key,
+ size_t keylen )
+{
+ int ret, version;
+ size_t len;
+ mbedcrypto_asn1_buf params;
+ unsigned char *p = (unsigned char *) key;
+ unsigned char *end = p + keylen;
+ mbedcrypto_pk_type_t pk_alg = MBEDCRYPTO_PK_NONE;
+ const mbedcrypto_pk_info_t *pk_info;
+
+ /*
+ * This function parses the PrivateKeyInfo object (PKCS#8 v1.2 = RFC 5208)
+ *
+ * PrivateKeyInfo ::= SEQUENCE {
+ * version Version,
+ * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
+ * privateKey PrivateKey,
+ * attributes [0] IMPLICIT Attributes OPTIONAL }
+ *
+ * Version ::= INTEGER
+ * PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
+ * PrivateKey ::= OCTET STRING
+ *
+ * The PrivateKey OCTET STRING is a SEC1 ECPrivateKey
+ */
+
+ if( ( ret = mbedcrypto_asn1_get_tag( &p, end, &len,
+ MBEDCRYPTO_ASN1_CONSTRUCTED | MBEDCRYPTO_ASN1_SEQUENCE ) ) != 0 )
+ {
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT + ret );
+ }
+
+ end = p + len;
+
+ if( ( ret = mbedcrypto_asn1_get_int( &p, end, &version ) ) != 0 )
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT + ret );
+
+ if( version != 0 )
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_VERSION + ret );
+
+ if( ( ret = pk_get_pk_alg( &p, end, &pk_alg, ¶ms ) ) != 0 )
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT + ret );
+
+ if( ( ret = mbedcrypto_asn1_get_tag( &p, end, &len, MBEDCRYPTO_ASN1_OCTET_STRING ) ) != 0 )
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT + ret );
+
+ if( len < 1 )
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT +
+ MBEDCRYPTO_ERR_ASN1_OUT_OF_DATA );
+
+ if( ( pk_info = mbedcrypto_pk_info_from_type( pk_alg ) ) == NULL )
+ return( MBEDCRYPTO_ERR_PK_UNKNOWN_PK_ALG );
+
+ if( ( ret = mbedcrypto_pk_setup( pk, pk_info ) ) != 0 )
+ return( ret );
+
+#if defined(MBEDCRYPTO_RSA_C)
+ if( pk_alg == MBEDCRYPTO_PK_RSA )
+ {
+ if( ( ret = pk_parse_key_pkcs1_der( mbedcrypto_pk_rsa( *pk ), p, len ) ) != 0 )
+ {
+ mbedcrypto_pk_free( pk );
+ return( ret );
+ }
+ } else
+#endif /* MBEDCRYPTO_RSA_C */
+#if defined(MBEDCRYPTO_ECP_C)
+ if( pk_alg == MBEDCRYPTO_PK_ECKEY || pk_alg == MBEDCRYPTO_PK_ECKEY_DH )
+ {
+ if( ( ret = pk_use_ecparams( ¶ms, &mbedcrypto_pk_ec( *pk )->grp ) ) != 0 ||
+ ( ret = pk_parse_key_sec1_der( mbedcrypto_pk_ec( *pk ), p, len ) ) != 0 )
+ {
+ mbedcrypto_pk_free( pk );
+ return( ret );
+ }
+ } else
+#endif /* MBEDCRYPTO_ECP_C */
+ return( MBEDCRYPTO_ERR_PK_UNKNOWN_PK_ALG );
+
+ return( 0 );
+}
+
+/*
+ * Parse an encrypted PKCS#8 encoded private key
+ *
+ * To save space, the decryption happens in-place on the given key buffer.
+ * Also, while this function may modify the keybuffer, it doesn't own it,
+ * and instead it is the responsibility of the caller to zeroize and properly
+ * free it after use.
+ *
+ */
+#if defined(MBEDCRYPTO_PKCS12_C) || defined(MBEDCRYPTO_PKCS5_C)
+static int pk_parse_key_pkcs8_encrypted_der(
+ mbedcrypto_pk_context *pk,
+ unsigned char *key, size_t keylen,
+ const unsigned char *pwd, size_t pwdlen )
+{
+ int ret, decrypted = 0;
+ size_t len;
+ unsigned char *buf;
+ unsigned char *p, *end;
+ mbedcrypto_asn1_buf pbe_alg_oid, pbe_params;
+#if defined(MBEDCRYPTO_PKCS12_C)
+ mbedcrypto_cipher_type_t cipher_alg;
+ mbedcrypto_md_type_t md_alg;
+#endif
+
+ p = key;
+ end = p + keylen;
+
+ if( pwdlen == 0 )
+ return( MBEDCRYPTO_ERR_PK_PASSWORD_REQUIRED );
+
+ /*
+ * This function parses the EncryptedPrivateKeyInfo object (PKCS#8)
+ *
+ * EncryptedPrivateKeyInfo ::= SEQUENCE {
+ * encryptionAlgorithm EncryptionAlgorithmIdentifier,
+ * encryptedData EncryptedData
+ * }
+ *
+ * EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ * EncryptedData ::= OCTET STRING
+ *
+ * The EncryptedData OCTET STRING is a PKCS#8 PrivateKeyInfo
+ *
+ */
+ if( ( ret = mbedcrypto_asn1_get_tag( &p, end, &len,
+ MBEDCRYPTO_ASN1_CONSTRUCTED | MBEDCRYPTO_ASN1_SEQUENCE ) ) != 0 )
+ {
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT + ret );
+ }
+
+ end = p + len;
+
+ if( ( ret = mbedcrypto_asn1_get_alg( &p, end, &pbe_alg_oid, &pbe_params ) ) != 0 )
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT + ret );
+
+ if( ( ret = mbedcrypto_asn1_get_tag( &p, end, &len, MBEDCRYPTO_ASN1_OCTET_STRING ) ) != 0 )
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT + ret );
+
+ buf = p;
+
+ /*
+ * Decrypt EncryptedData with appropriate PBE
+ */
+#if defined(MBEDCRYPTO_PKCS12_C)
+ if( mbedcrypto_oid_get_pkcs12_pbe_alg( &pbe_alg_oid, &md_alg, &cipher_alg ) == 0 )
+ {
+ if( ( ret = mbedcrypto_pkcs12_pbe( &pbe_params, MBEDCRYPTO_PKCS12_PBE_DECRYPT,
+ cipher_alg, md_alg,
+ pwd, pwdlen, p, len, buf ) ) != 0 )
+ {
+ if( ret == MBEDCRYPTO_ERR_PKCS12_PASSWORD_MISMATCH )
+ return( MBEDCRYPTO_ERR_PK_PASSWORD_MISMATCH );
+
+ return( ret );
+ }
+
+ decrypted = 1;
+ }
+ else if( MBEDCRYPTO_OID_CMP( MBEDCRYPTO_OID_PKCS12_PBE_SHA1_RC4_128, &pbe_alg_oid ) == 0 )
+ {
+ if( ( ret = mbedcrypto_pkcs12_pbe_sha1_rc4_128( &pbe_params,
+ MBEDCRYPTO_PKCS12_PBE_DECRYPT,
+ pwd, pwdlen,
+ p, len, buf ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ // Best guess for password mismatch when using RC4. If first tag is
+ // not MBEDCRYPTO_ASN1_CONSTRUCTED | MBEDCRYPTO_ASN1_SEQUENCE
+ //
+ if( *buf != ( MBEDCRYPTO_ASN1_CONSTRUCTED | MBEDCRYPTO_ASN1_SEQUENCE ) )
+ return( MBEDCRYPTO_ERR_PK_PASSWORD_MISMATCH );
+
+ decrypted = 1;
+ }
+ else
+#endif /* MBEDCRYPTO_PKCS12_C */
+#if defined(MBEDCRYPTO_PKCS5_C)
+ if( MBEDCRYPTO_OID_CMP( MBEDCRYPTO_OID_PKCS5_PBES2, &pbe_alg_oid ) == 0 )
+ {
+ if( ( ret = mbedcrypto_pkcs5_pbes2( &pbe_params, MBEDCRYPTO_PKCS5_DECRYPT, pwd, pwdlen,
+ p, len, buf ) ) != 0 )
+ {
+ if( ret == MBEDCRYPTO_ERR_PKCS5_PASSWORD_MISMATCH )
+ return( MBEDCRYPTO_ERR_PK_PASSWORD_MISMATCH );
+
+ return( ret );
+ }
+
+ decrypted = 1;
+ }
+ else
+#endif /* MBEDCRYPTO_PKCS5_C */
+ {
+ ((void) pwd);
+ }
+
+ if( decrypted == 0 )
+ return( MBEDCRYPTO_ERR_PK_FEATURE_UNAVAILABLE );
+
+ return( pk_parse_key_pkcs8_unencrypted_der( pk, buf, len ) );
+}
+#endif /* MBEDCRYPTO_PKCS12_C || MBEDCRYPTO_PKCS5_C */
+
+/*
+ * Parse a private key
+ */
+int mbedcrypto_pk_parse_key( mbedcrypto_pk_context *pk,
+ const unsigned char *key, size_t keylen,
+ const unsigned char *pwd, size_t pwdlen )
+{
+ int ret;
+ const mbedcrypto_pk_info_t *pk_info;
+
+#if defined(MBEDCRYPTO_PEM_PARSE_C)
+ size_t len;
+ mbedcrypto_pem_context pem;
+
+ mbedcrypto_pem_init( &pem );
+
+#if defined(MBEDCRYPTO_RSA_C)
+ /* Avoid calling mbedcrypto_pem_read_buffer() on non-null-terminated string */
+ if( keylen == 0 || key[keylen - 1] != '\0' )
+ ret = MBEDCRYPTO_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
+ else
+ ret = mbedcrypto_pem_read_buffer( &pem,
+ "-----BEGIN RSA PRIVATE KEY-----",
+ "-----END RSA PRIVATE KEY-----",
+ key, pwd, pwdlen, &len );
+
+ if( ret == 0 )
+ {
+ pk_info = mbedcrypto_pk_info_from_type( MBEDCRYPTO_PK_RSA );
+ if( ( ret = mbedcrypto_pk_setup( pk, pk_info ) ) != 0 ||
+ ( ret = pk_parse_key_pkcs1_der( mbedcrypto_pk_rsa( *pk ),
+ pem.buf, pem.buflen ) ) != 0 )
+ {
+ mbedcrypto_pk_free( pk );
+ }
+
+ mbedcrypto_pem_free( &pem );
+ return( ret );
+ }
+ else if( ret == MBEDCRYPTO_ERR_PEM_PASSWORD_MISMATCH )
+ return( MBEDCRYPTO_ERR_PK_PASSWORD_MISMATCH );
+ else if( ret == MBEDCRYPTO_ERR_PEM_PASSWORD_REQUIRED )
+ return( MBEDCRYPTO_ERR_PK_PASSWORD_REQUIRED );
+ else if( ret != MBEDCRYPTO_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
+ return( ret );
+#endif /* MBEDCRYPTO_RSA_C */
+
+#if defined(MBEDCRYPTO_ECP_C)
+ /* Avoid calling mbedcrypto_pem_read_buffer() on non-null-terminated string */
+ if( keylen == 0 || key[keylen - 1] != '\0' )
+ ret = MBEDCRYPTO_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
+ else
+ ret = mbedcrypto_pem_read_buffer( &pem,
+ "-----BEGIN EC PRIVATE KEY-----",
+ "-----END EC PRIVATE KEY-----",
+ key, pwd, pwdlen, &len );
+ if( ret == 0 )
+ {
+ pk_info = mbedcrypto_pk_info_from_type( MBEDCRYPTO_PK_ECKEY );
+
+ if( ( ret = mbedcrypto_pk_setup( pk, pk_info ) ) != 0 ||
+ ( ret = pk_parse_key_sec1_der( mbedcrypto_pk_ec( *pk ),
+ pem.buf, pem.buflen ) ) != 0 )
+ {
+ mbedcrypto_pk_free( pk );
+ }
+
+ mbedcrypto_pem_free( &pem );
+ return( ret );
+ }
+ else if( ret == MBEDCRYPTO_ERR_PEM_PASSWORD_MISMATCH )
+ return( MBEDCRYPTO_ERR_PK_PASSWORD_MISMATCH );
+ else if( ret == MBEDCRYPTO_ERR_PEM_PASSWORD_REQUIRED )
+ return( MBEDCRYPTO_ERR_PK_PASSWORD_REQUIRED );
+ else if( ret != MBEDCRYPTO_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
+ return( ret );
+#endif /* MBEDCRYPTO_ECP_C */
+
+ /* Avoid calling mbedcrypto_pem_read_buffer() on non-null-terminated string */
+ if( keylen == 0 || key[keylen - 1] != '\0' )
+ ret = MBEDCRYPTO_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
+ else
+ ret = mbedcrypto_pem_read_buffer( &pem,
+ "-----BEGIN PRIVATE KEY-----",
+ "-----END PRIVATE KEY-----",
+ key, NULL, 0, &len );
+ if( ret == 0 )
+ {
+ if( ( ret = pk_parse_key_pkcs8_unencrypted_der( pk,
+ pem.buf, pem.buflen ) ) != 0 )
+ {
+ mbedcrypto_pk_free( pk );
+ }
+
+ mbedcrypto_pem_free( &pem );
+ return( ret );
+ }
+ else if( ret != MBEDCRYPTO_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
+ return( ret );
+
+#if defined(MBEDCRYPTO_PKCS12_C) || defined(MBEDCRYPTO_PKCS5_C)
+ /* Avoid calling mbedcrypto_pem_read_buffer() on non-null-terminated string */
+ if( keylen == 0 || key[keylen - 1] != '\0' )
+ ret = MBEDCRYPTO_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
+ else
+ ret = mbedcrypto_pem_read_buffer( &pem,
+ "-----BEGIN ENCRYPTED PRIVATE KEY-----",
+ "-----END ENCRYPTED PRIVATE KEY-----",
+ key, NULL, 0, &len );
+ if( ret == 0 )
+ {
+ if( ( ret = pk_parse_key_pkcs8_encrypted_der( pk,
+ pem.buf, pem.buflen,
+ pwd, pwdlen ) ) != 0 )
+ {
+ mbedcrypto_pk_free( pk );
+ }
+
+ mbedcrypto_pem_free( &pem );
+ return( ret );
+ }
+ else if( ret != MBEDCRYPTO_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
+ return( ret );
+#endif /* MBEDCRYPTO_PKCS12_C || MBEDCRYPTO_PKCS5_C */
+#else
+ ((void) ret);
+ ((void) pwd);
+ ((void) pwdlen);
+#endif /* MBEDCRYPTO_PEM_PARSE_C */
+
+ /*
+ * At this point we only know it's not a PEM formatted key. Could be any
+ * of the known DER encoded private key formats
+ *
+ * We try the different DER format parsers to see if one passes without
+ * error
+ */
+#if defined(MBEDCRYPTO_PKCS12_C) || defined(MBEDCRYPTO_PKCS5_C)
+ {
+ unsigned char *key_copy;
+
+ if( keylen == 0 )
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT );
+
+ if( ( key_copy = mbedcrypto_calloc( 1, keylen ) ) == NULL )
+ return( MBEDCRYPTO_ERR_PK_ALLOC_FAILED );
+
+ memcpy( key_copy, key, keylen );
+
+ ret = pk_parse_key_pkcs8_encrypted_der( pk, key_copy, keylen,
+ pwd, pwdlen );
+
+ mbedcrypto_platform_zeroize( key_copy, keylen );
+ mbedcrypto_free( key_copy );
+ }
+
+ if( ret == 0 )
+ return( 0 );
+
+ mbedcrypto_pk_free( pk );
+
+ if( ret == MBEDCRYPTO_ERR_PK_PASSWORD_MISMATCH )
+ {
+ return( ret );
+ }
+#endif /* MBEDCRYPTO_PKCS12_C || MBEDCRYPTO_PKCS5_C */
+
+ if( ( ret = pk_parse_key_pkcs8_unencrypted_der( pk, key, keylen ) ) == 0 )
+ return( 0 );
+
+ mbedcrypto_pk_free( pk );
+
+#if defined(MBEDCRYPTO_RSA_C)
+
+ pk_info = mbedcrypto_pk_info_from_type( MBEDCRYPTO_PK_RSA );
+ if( ( ret = mbedcrypto_pk_setup( pk, pk_info ) ) != 0 ||
+ ( ret = pk_parse_key_pkcs1_der( mbedcrypto_pk_rsa( *pk ),
+ key, keylen ) ) != 0 )
+ {
+ mbedcrypto_pk_free( pk );
+ }
+ else
+ {
+ return( 0 );
+ }
+
+#endif /* MBEDCRYPTO_RSA_C */
+
+#if defined(MBEDCRYPTO_ECP_C)
+
+ pk_info = mbedcrypto_pk_info_from_type( MBEDCRYPTO_PK_ECKEY );
+ if( ( ret = mbedcrypto_pk_setup( pk, pk_info ) ) != 0 ||
+ ( ret = pk_parse_key_sec1_der( mbedcrypto_pk_ec( *pk ),
+ key, keylen ) ) != 0 )
+ {
+ mbedcrypto_pk_free( pk );
+ }
+ else
+ {
+ return( 0 );
+ }
+
+#endif /* MBEDCRYPTO_ECP_C */
+
+ return( MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT );
+}
+
+/*
+ * Parse a public key
+ */
+int mbedcrypto_pk_parse_public_key( mbedcrypto_pk_context *ctx,
+ const unsigned char *key, size_t keylen )
+{
+ int ret;
+ unsigned char *p;
+#if defined(MBEDCRYPTO_RSA_C)
+ const mbedcrypto_pk_info_t *pk_info;
+#endif
+#if defined(MBEDCRYPTO_PEM_PARSE_C)
+ size_t len;
+ mbedcrypto_pem_context pem;
+
+ mbedcrypto_pem_init( &pem );
+#if defined(MBEDCRYPTO_RSA_C)
+ /* Avoid calling mbedcrypto_pem_read_buffer() on non-null-terminated string */
+ if( keylen == 0 || key[keylen - 1] != '\0' )
+ ret = MBEDCRYPTO_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
+ else
+ ret = mbedcrypto_pem_read_buffer( &pem,
+ "-----BEGIN RSA PUBLIC KEY-----",
+ "-----END RSA PUBLIC KEY-----",
+ key, NULL, 0, &len );
+
+ if( ret == 0 )
+ {
+ p = pem.buf;
+ if( ( pk_info = mbedcrypto_pk_info_from_type( MBEDCRYPTO_PK_RSA ) ) == NULL )
+ return( MBEDCRYPTO_ERR_PK_UNKNOWN_PK_ALG );
+
+ if( ( ret = mbedcrypto_pk_setup( ctx, pk_info ) ) != 0 )
+ return( ret );
+
+ if ( ( ret = pk_get_rsapubkey( &p, p + pem.buflen, mbedcrypto_pk_rsa( *ctx ) ) ) != 0 )
+ mbedcrypto_pk_free( ctx );
+
+ mbedcrypto_pem_free( &pem );
+ return( ret );
+ }
+ else if( ret != MBEDCRYPTO_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
+ {
+ mbedcrypto_pem_free( &pem );
+ return( ret );
+ }
+#endif /* MBEDCRYPTO_RSA_C */
+
+ /* Avoid calling mbedcrypto_pem_read_buffer() on non-null-terminated string */
+ if( keylen == 0 || key[keylen - 1] != '\0' )
+ ret = MBEDCRYPTO_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
+ else
+ ret = mbedcrypto_pem_read_buffer( &pem,
+ "-----BEGIN PUBLIC KEY-----",
+ "-----END PUBLIC KEY-----",
+ key, NULL, 0, &len );
+
+ if( ret == 0 )
+ {
+ /*
+ * Was PEM encoded
+ */
+ p = pem.buf;
+
+ ret = mbedcrypto_pk_parse_subpubkey( &p, p + pem.buflen, ctx );
+ mbedcrypto_pem_free( &pem );
+ return( ret );
+ }
+ else if( ret != MBEDCRYPTO_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
+ {
+ mbedcrypto_pem_free( &pem );
+ return( ret );
+ }
+ mbedcrypto_pem_free( &pem );
+#endif /* MBEDCRYPTO_PEM_PARSE_C */
+
+#if defined(MBEDCRYPTO_RSA_C)
+ if( ( pk_info = mbedcrypto_pk_info_from_type( MBEDCRYPTO_PK_RSA ) ) == NULL )
+ return( MBEDCRYPTO_ERR_PK_UNKNOWN_PK_ALG );
+
+ if( ( ret = mbedcrypto_pk_setup( ctx, pk_info ) ) != 0 )
+ return( ret );
+
+ p = (unsigned char *)key;
+ ret = pk_get_rsapubkey( &p, p + keylen, mbedcrypto_pk_rsa( *ctx ) );
+ if( ret == 0 )
+ {
+ return( ret );
+ }
+ mbedcrypto_pk_free( ctx );
+ if( ret != ( MBEDCRYPTO_ERR_PK_INVALID_PUBKEY + MBEDCRYPTO_ERR_ASN1_UNEXPECTED_TAG ) )
+ {
+ return( ret );
+ }
+#endif /* MBEDCRYPTO_RSA_C */
+ p = (unsigned char *) key;
+
+ ret = mbedcrypto_pk_parse_subpubkey( &p, p + keylen, ctx );
+
+ return( ret );
+}
+
+#endif /* MBEDCRYPTO_PK_PARSE_C */
diff --git a/library/pkwrite.c b/library/pkwrite.c
new file mode 100644
index 0000000..603c89e
--- /dev/null
+++ b/library/pkwrite.c
@@ -0,0 +1,515 @@
+/*
+ * Public Key layer for writing key files and structures
+ *
+ * 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 Crypto (https://tls.mbed.org)
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_PK_WRITE_C)
+
+#include "mbedcrypto/pk.h"
+#include "mbedcrypto/asn1write.h"
+#include "mbedcrypto/oid.h"
+
+#include <string.h>
+
+#if defined(MBEDCRYPTO_RSA_C)
+#include "mbedcrypto/rsa.h"
+#endif
+#if defined(MBEDCRYPTO_ECP_C)
+#include "mbedcrypto/ecp.h"
+#endif
+#if defined(MBEDCRYPTO_ECDSA_C)
+#include "mbedcrypto/ecdsa.h"
+#endif
+#if defined(MBEDCRYPTO_PEM_WRITE_C)
+#include "mbedcrypto/pem.h"
+#endif
+
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#include <stdlib.h>
+#define mbedcrypto_calloc calloc
+#define mbedcrypto_free free
+#endif
+
+#if defined(MBEDCRYPTO_RSA_C)
+/*
+ * RSAPublicKey ::= SEQUENCE {
+ * modulus INTEGER, -- n
+ * publicExponent INTEGER -- e
+ * }
+ */
+static int pk_write_rsa_pubkey( unsigned char **p, unsigned char *start,
+ mbedcrypto_rsa_context *rsa )
+{
+ int ret;
+ size_t len = 0;
+ mbedcrypto_mpi T;
+
+ mbedcrypto_mpi_init( &T );
+
+ /* Export E */
+ if ( ( ret = mbedcrypto_rsa_export( rsa, NULL, NULL, NULL, NULL, &T ) ) != 0 ||
+ ( ret = mbedcrypto_asn1_write_mpi( p, start, &T ) ) < 0 )
+ goto end_of_export;
+ len += ret;
+
+ /* Export N */
+ if ( ( ret = mbedcrypto_rsa_export( rsa, &T, NULL, NULL, NULL, NULL ) ) != 0 ||
+ ( ret = mbedcrypto_asn1_write_mpi( p, start, &T ) ) < 0 )
+ goto end_of_export;
+ len += ret;
+
+end_of_export:
+
+ mbedcrypto_mpi_free( &T );
+ if( ret < 0 )
+ return( ret );
+
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_len( p, start, len ) );
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_tag( p, start, MBEDCRYPTO_ASN1_CONSTRUCTED |
+ MBEDCRYPTO_ASN1_SEQUENCE ) );
+
+ return( (int) len );
+}
+#endif /* MBEDCRYPTO_RSA_C */
+
+#if defined(MBEDCRYPTO_ECP_C)
+/*
+ * EC public key is an EC point
+ */
+static int pk_write_ec_pubkey( unsigned char **p, unsigned char *start,
+ mbedcrypto_ecp_keypair *ec )
+{
+ int ret;
+ size_t len = 0;
+ unsigned char buf[MBEDCRYPTO_ECP_MAX_PT_LEN];
+
+ if( ( ret = mbedcrypto_ecp_point_write_binary( &ec->grp, &ec->Q,
+ MBEDCRYPTO_ECP_PF_UNCOMPRESSED,
+ &len, buf, sizeof( buf ) ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ if( *p < start || (size_t)( *p - start ) < len )
+ return( MBEDCRYPTO_ERR_ASN1_BUF_TOO_SMALL );
+
+ *p -= len;
+ memcpy( *p, buf, len );
+
+ return( (int) len );
+}
+
+/*
+ * ECParameters ::= CHOICE {
+ * namedCurve OBJECT IDENTIFIER
+ * }
+ */
+static int pk_write_ec_param( unsigned char **p, unsigned char *start,
+ mbedcrypto_ecp_keypair *ec )
+{
+ int ret;
+ size_t len = 0;
+ const char *oid;
+ size_t oid_len;
+
+ if( ( ret = mbedcrypto_oid_get_oid_by_ec_grp( ec->grp.id, &oid, &oid_len ) ) != 0 )
+ return( ret );
+
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_oid( p, start, oid, oid_len ) );
+
+ return( (int) len );
+}
+#endif /* MBEDCRYPTO_ECP_C */
+
+int mbedcrypto_pk_write_pubkey( unsigned char **p, unsigned char *start,
+ const mbedcrypto_pk_context *key )
+{
+ int ret;
+ size_t len = 0;
+
+#if defined(MBEDCRYPTO_RSA_C)
+ if( mbedcrypto_pk_get_type( key ) == MBEDCRYPTO_PK_RSA )
+ MBEDCRYPTO_ASN1_CHK_ADD( len, pk_write_rsa_pubkey( p, start, mbedcrypto_pk_rsa( *key ) ) );
+ else
+#endif
+#if defined(MBEDCRYPTO_ECP_C)
+ if( mbedcrypto_pk_get_type( key ) == MBEDCRYPTO_PK_ECKEY )
+ MBEDCRYPTO_ASN1_CHK_ADD( len, pk_write_ec_pubkey( p, start, mbedcrypto_pk_ec( *key ) ) );
+ else
+#endif
+ return( MBEDCRYPTO_ERR_PK_FEATURE_UNAVAILABLE );
+
+ return( (int) len );
+}
+
+int mbedcrypto_pk_write_pubkey_der( mbedcrypto_pk_context *key, unsigned char *buf, size_t size )
+{
+ int ret;
+ unsigned char *c;
+ size_t len = 0, par_len = 0, oid_len;
+ const char *oid;
+
+ c = buf + size;
+
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_pk_write_pubkey( &c, buf, key ) );
+
+ if( c - buf < 1 )
+ return( MBEDCRYPTO_ERR_ASN1_BUF_TOO_SMALL );
+
+ /*
+ * SubjectPublicKeyInfo ::= SEQUENCE {
+ * algorithm AlgorithmIdentifier,
+ * subjectPublicKey BIT STRING }
+ */
+ *--c = 0;
+ len += 1;
+
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_len( &c, buf, len ) );
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_tag( &c, buf, MBEDCRYPTO_ASN1_BIT_STRING ) );
+
+ if( ( ret = mbedcrypto_oid_get_oid_by_pk_alg( mbedcrypto_pk_get_type( key ),
+ &oid, &oid_len ) ) != 0 )
+ {
+ return( ret );
+ }
+
+#if defined(MBEDCRYPTO_ECP_C)
+ if( mbedcrypto_pk_get_type( key ) == MBEDCRYPTO_PK_ECKEY )
+ {
+ MBEDCRYPTO_ASN1_CHK_ADD( par_len, pk_write_ec_param( &c, buf, mbedcrypto_pk_ec( *key ) ) );
+ }
+#endif
+
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_algorithm_identifier( &c, buf, oid, oid_len,
+ par_len ) );
+
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_len( &c, buf, len ) );
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_tag( &c, buf, MBEDCRYPTO_ASN1_CONSTRUCTED |
+ MBEDCRYPTO_ASN1_SEQUENCE ) );
+
+ return( (int) len );
+}
+
+int mbedcrypto_pk_write_key_der( mbedcrypto_pk_context *key, unsigned char *buf, size_t size )
+{
+ int ret;
+ unsigned char *c = buf + size;
+ size_t len = 0;
+
+#if defined(MBEDCRYPTO_RSA_C)
+ if( mbedcrypto_pk_get_type( key ) == MBEDCRYPTO_PK_RSA )
+ {
+ mbedcrypto_mpi T; /* Temporary holding the exported parameters */
+ mbedcrypto_rsa_context *rsa = mbedcrypto_pk_rsa( *key );
+
+ /*
+ * Export the parameters one after another to avoid simultaneous copies.
+ */
+
+ mbedcrypto_mpi_init( &T );
+
+ /* Export QP */
+ if( ( ret = mbedcrypto_rsa_export_crt( rsa, NULL, NULL, &T ) ) != 0 ||
+ ( ret = mbedcrypto_asn1_write_mpi( &c, buf, &T ) ) < 0 )
+ goto end_of_export;
+ len += ret;
+
+ /* Export DQ */
+ if( ( ret = mbedcrypto_rsa_export_crt( rsa, NULL, &T, NULL ) ) != 0 ||
+ ( ret = mbedcrypto_asn1_write_mpi( &c, buf, &T ) ) < 0 )
+ goto end_of_export;
+ len += ret;
+
+ /* Export DP */
+ if( ( ret = mbedcrypto_rsa_export_crt( rsa, &T, NULL, NULL ) ) != 0 ||
+ ( ret = mbedcrypto_asn1_write_mpi( &c, buf, &T ) ) < 0 )
+ goto end_of_export;
+ len += ret;
+
+ /* Export Q */
+ if ( ( ret = mbedcrypto_rsa_export( rsa, NULL, NULL,
+ &T, NULL, NULL ) ) != 0 ||
+ ( ret = mbedcrypto_asn1_write_mpi( &c, buf, &T ) ) < 0 )
+ goto end_of_export;
+ len += ret;
+
+ /* Export P */
+ if ( ( ret = mbedcrypto_rsa_export( rsa, NULL, &T,
+ NULL, NULL, NULL ) ) != 0 ||
+ ( ret = mbedcrypto_asn1_write_mpi( &c, buf, &T ) ) < 0 )
+ goto end_of_export;
+ len += ret;
+
+ /* Export D */
+ if ( ( ret = mbedcrypto_rsa_export( rsa, NULL, NULL,
+ NULL, &T, NULL ) ) != 0 ||
+ ( ret = mbedcrypto_asn1_write_mpi( &c, buf, &T ) ) < 0 )
+ goto end_of_export;
+ len += ret;
+
+ /* Export E */
+ if ( ( ret = mbedcrypto_rsa_export( rsa, NULL, NULL,
+ NULL, NULL, &T ) ) != 0 ||
+ ( ret = mbedcrypto_asn1_write_mpi( &c, buf, &T ) ) < 0 )
+ goto end_of_export;
+ len += ret;
+
+ /* Export N */
+ if ( ( ret = mbedcrypto_rsa_export( rsa, &T, NULL,
+ NULL, NULL, NULL ) ) != 0 ||
+ ( ret = mbedcrypto_asn1_write_mpi( &c, buf, &T ) ) < 0 )
+ goto end_of_export;
+ len += ret;
+
+ end_of_export:
+
+ mbedcrypto_mpi_free( &T );
+ if( ret < 0 )
+ return( ret );
+
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_int( &c, buf, 0 ) );
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_len( &c, buf, len ) );
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_tag( &c,
+ buf, MBEDCRYPTO_ASN1_CONSTRUCTED |
+ MBEDCRYPTO_ASN1_SEQUENCE ) );
+ }
+ else
+#endif /* MBEDCRYPTO_RSA_C */
+#if defined(MBEDCRYPTO_ECP_C)
+ if( mbedcrypto_pk_get_type( key ) == MBEDCRYPTO_PK_ECKEY )
+ {
+ mbedcrypto_ecp_keypair *ec = mbedcrypto_pk_ec( *key );
+ size_t pub_len = 0, par_len = 0;
+
+ /*
+ * RFC 5915, or SEC1 Appendix C.4
+ *
+ * ECPrivateKey ::= SEQUENCE {
+ * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
+ * privateKey OCTET STRING,
+ * parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
+ * publicKey [1] BIT STRING OPTIONAL
+ * }
+ */
+
+ /* publicKey */
+ MBEDCRYPTO_ASN1_CHK_ADD( pub_len, pk_write_ec_pubkey( &c, buf, ec ) );
+
+ if( c - buf < 1 )
+ return( MBEDCRYPTO_ERR_ASN1_BUF_TOO_SMALL );
+ *--c = 0;
+ pub_len += 1;
+
+ MBEDCRYPTO_ASN1_CHK_ADD( pub_len, mbedcrypto_asn1_write_len( &c, buf, pub_len ) );
+ MBEDCRYPTO_ASN1_CHK_ADD( pub_len, mbedcrypto_asn1_write_tag( &c, buf, MBEDCRYPTO_ASN1_BIT_STRING ) );
+
+ MBEDCRYPTO_ASN1_CHK_ADD( pub_len, mbedcrypto_asn1_write_len( &c, buf, pub_len ) );
+ MBEDCRYPTO_ASN1_CHK_ADD( pub_len, mbedcrypto_asn1_write_tag( &c, buf,
+ MBEDCRYPTO_ASN1_CONTEXT_SPECIFIC | MBEDCRYPTO_ASN1_CONSTRUCTED | 1 ) );
+ len += pub_len;
+
+ /* parameters */
+ MBEDCRYPTO_ASN1_CHK_ADD( par_len, pk_write_ec_param( &c, buf, ec ) );
+
+ MBEDCRYPTO_ASN1_CHK_ADD( par_len, mbedcrypto_asn1_write_len( &c, buf, par_len ) );
+ MBEDCRYPTO_ASN1_CHK_ADD( par_len, mbedcrypto_asn1_write_tag( &c, buf,
+ MBEDCRYPTO_ASN1_CONTEXT_SPECIFIC | MBEDCRYPTO_ASN1_CONSTRUCTED | 0 ) );
+ len += par_len;
+
+ /* privateKey: write as MPI then fix tag */
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_mpi( &c, buf, &ec->d ) );
+ *c = MBEDCRYPTO_ASN1_OCTET_STRING;
+
+ /* version */
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_int( &c, buf, 1 ) );
+
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_len( &c, buf, len ) );
+ MBEDCRYPTO_ASN1_CHK_ADD( len, mbedcrypto_asn1_write_tag( &c, buf, MBEDCRYPTO_ASN1_CONSTRUCTED |
+ MBEDCRYPTO_ASN1_SEQUENCE ) );
+ }
+ else
+#endif /* MBEDCRYPTO_ECP_C */
+ return( MBEDCRYPTO_ERR_PK_FEATURE_UNAVAILABLE );
+
+ return( (int) len );
+}
+
+#if defined(MBEDCRYPTO_PEM_WRITE_C)
+
+#define PEM_BEGIN_PUBLIC_KEY "-----BEGIN PUBLIC KEY-----\n"
+#define PEM_END_PUBLIC_KEY "-----END PUBLIC KEY-----\n"
+
+#define PEM_BEGIN_PRIVATE_KEY_RSA "-----BEGIN RSA PRIVATE KEY-----\n"
+#define PEM_END_PRIVATE_KEY_RSA "-----END RSA PRIVATE KEY-----\n"
+#define PEM_BEGIN_PRIVATE_KEY_EC "-----BEGIN EC PRIVATE KEY-----\n"
+#define PEM_END_PRIVATE_KEY_EC "-----END EC PRIVATE KEY-----\n"
+
+/*
+ * Max sizes of key per types. Shown as tag + len (+ content).
+ */
+
+#if defined(MBEDCRYPTO_RSA_C)
+/*
+ * RSA public keys:
+ * SubjectPublicKeyInfo ::= SEQUENCE { 1 + 3
+ * algorithm AlgorithmIdentifier, 1 + 1 (sequence)
+ * + 1 + 1 + 9 (rsa oid)
+ * + 1 + 1 (params null)
+ * subjectPublicKey BIT STRING } 1 + 3 + (1 + below)
+ * RSAPublicKey ::= SEQUENCE { 1 + 3
+ * modulus INTEGER, -- n 1 + 3 + MPI_MAX + 1
+ * publicExponent INTEGER -- e 1 + 3 + MPI_MAX + 1
+ * }
+ */
+#define RSA_PUB_DER_MAX_BYTES 38 + 2 * MBEDCRYPTO_MPI_MAX_SIZE
+
+/*
+ * RSA private keys:
+ * RSAPrivateKey ::= SEQUENCE { 1 + 3
+ * version Version, 1 + 1 + 1
+ * modulus INTEGER, 1 + 3 + MPI_MAX + 1
+ * publicExponent INTEGER, 1 + 3 + MPI_MAX + 1
+ * privateExponent INTEGER, 1 + 3 + MPI_MAX + 1
+ * prime1 INTEGER, 1 + 3 + MPI_MAX / 2 + 1
+ * prime2 INTEGER, 1 + 3 + MPI_MAX / 2 + 1
+ * exponent1 INTEGER, 1 + 3 + MPI_MAX / 2 + 1
+ * exponent2 INTEGER, 1 + 3 + MPI_MAX / 2 + 1
+ * coefficient INTEGER, 1 + 3 + MPI_MAX / 2 + 1
+ * otherPrimeInfos OtherPrimeInfos OPTIONAL 0 (not supported)
+ * }
+ */
+#define MPI_MAX_SIZE_2 MBEDCRYPTO_MPI_MAX_SIZE / 2 + \
+ MBEDCRYPTO_MPI_MAX_SIZE % 2
+#define RSA_PRV_DER_MAX_BYTES 47 + 3 * MBEDCRYPTO_MPI_MAX_SIZE \
+ + 5 * MPI_MAX_SIZE_2
+
+#else /* MBEDCRYPTO_RSA_C */
+
+#define RSA_PUB_DER_MAX_BYTES 0
+#define RSA_PRV_DER_MAX_BYTES 0
+
+#endif /* MBEDCRYPTO_RSA_C */
+
+#if defined(MBEDCRYPTO_ECP_C)
+/*
+ * EC public keys:
+ * SubjectPublicKeyInfo ::= SEQUENCE { 1 + 2
+ * algorithm AlgorithmIdentifier, 1 + 1 (sequence)
+ * + 1 + 1 + 7 (ec oid)
+ * + 1 + 1 + 9 (namedCurve oid)
+ * subjectPublicKey BIT STRING 1 + 2 + 1 [1]
+ * + 1 (point format) [1]
+ * + 2 * ECP_MAX (coords) [1]
+ * }
+ */
+#define ECP_PUB_DER_MAX_BYTES 30 + 2 * MBEDCRYPTO_ECP_MAX_BYTES
+
+/*
+ * EC private keys:
+ * ECPrivateKey ::= SEQUENCE { 1 + 2
+ * version INTEGER , 1 + 1 + 1
+ * privateKey OCTET STRING, 1 + 1 + ECP_MAX
+ * parameters [0] ECParameters OPTIONAL, 1 + 1 + (1 + 1 + 9)
+ * publicKey [1] BIT STRING OPTIONAL 1 + 2 + [1] above
+ * }
+ */
+#define ECP_PRV_DER_MAX_BYTES 29 + 3 * MBEDCRYPTO_ECP_MAX_BYTES
+
+#else /* MBEDCRYPTO_ECP_C */
+
+#define ECP_PUB_DER_MAX_BYTES 0
+#define ECP_PRV_DER_MAX_BYTES 0
+
+#endif /* MBEDCRYPTO_ECP_C */
+
+#define PUB_DER_MAX_BYTES RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \
+ RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES
+#define PRV_DER_MAX_BYTES RSA_PRV_DER_MAX_BYTES > ECP_PRV_DER_MAX_BYTES ? \
+ RSA_PRV_DER_MAX_BYTES : ECP_PRV_DER_MAX_BYTES
+
+int mbedcrypto_pk_write_pubkey_pem( mbedcrypto_pk_context *key, unsigned char *buf, size_t size )
+{
+ int ret;
+ unsigned char output_buf[PUB_DER_MAX_BYTES];
+ size_t olen = 0;
+
+ if( ( ret = mbedcrypto_pk_write_pubkey_der( key, output_buf,
+ sizeof(output_buf) ) ) < 0 )
+ {
+ return( ret );
+ }
+
+ if( ( ret = mbedcrypto_pem_write_buffer( PEM_BEGIN_PUBLIC_KEY, PEM_END_PUBLIC_KEY,
+ output_buf + sizeof(output_buf) - ret,
+ ret, buf, size, &olen ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ return( 0 );
+}
+
+int mbedcrypto_pk_write_key_pem( mbedcrypto_pk_context *key, unsigned char *buf, size_t size )
+{
+ int ret;
+ unsigned char output_buf[PRV_DER_MAX_BYTES];
+ const char *begin, *end;
+ size_t olen = 0;
+
+ if( ( ret = mbedcrypto_pk_write_key_der( key, output_buf, sizeof(output_buf) ) ) < 0 )
+ return( ret );
+
+#if defined(MBEDCRYPTO_RSA_C)
+ if( mbedcrypto_pk_get_type( key ) == MBEDCRYPTO_PK_RSA )
+ {
+ begin = PEM_BEGIN_PRIVATE_KEY_RSA;
+ end = PEM_END_PRIVATE_KEY_RSA;
+ }
+ else
+#endif
+#if defined(MBEDCRYPTO_ECP_C)
+ if( mbedcrypto_pk_get_type( key ) == MBEDCRYPTO_PK_ECKEY )
+ {
+ begin = PEM_BEGIN_PRIVATE_KEY_EC;
+ end = PEM_END_PRIVATE_KEY_EC;
+ }
+ else
+#endif
+ return( MBEDCRYPTO_ERR_PK_FEATURE_UNAVAILABLE );
+
+ if( ( ret = mbedcrypto_pem_write_buffer( begin, end,
+ output_buf + sizeof(output_buf) - ret,
+ ret, buf, size, &olen ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ return( 0 );
+}
+#endif /* MBEDCRYPTO_PEM_WRITE_C */
+
+#endif /* MBEDCRYPTO_PK_WRITE_C */
diff --git a/library/platform.c b/library/platform.c
new file mode 100644
index 0000000..40a3099
--- /dev/null
+++ b/library/platform.c
@@ -0,0 +1,329 @@
+/*
+ * Platform abstraction layer
+ *
+ * Copyright (C) 2006-2016, 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 Crypto (https://tls.mbed.org)
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_PLATFORM_C)
+
+#include "mbedcrypto/platform.h"
+#include "mbedcrypto/platform_util.h"
+
+#if defined(MBEDCRYPTO_PLATFORM_MEMORY)
+#if !defined(MBEDCRYPTO_PLATFORM_STD_CALLOC)
+static void *platform_calloc_uninit( size_t n, size_t size )
+{
+ ((void) n);
+ ((void) size);
+ return( NULL );
+}
+
+#define MBEDCRYPTO_PLATFORM_STD_CALLOC platform_calloc_uninit
+#endif /* !MBEDCRYPTO_PLATFORM_STD_CALLOC */
+
+#if !defined(MBEDCRYPTO_PLATFORM_STD_FREE)
+static void platform_free_uninit( void *ptr )
+{
+ ((void) ptr);
+}
+
+#define MBEDCRYPTO_PLATFORM_STD_FREE platform_free_uninit
+#endif /* !MBEDCRYPTO_PLATFORM_STD_FREE */
+
+void * (*mbedcrypto_calloc)( size_t, size_t ) = MBEDCRYPTO_PLATFORM_STD_CALLOC;
+void (*mbedcrypto_free)( void * ) = MBEDCRYPTO_PLATFORM_STD_FREE;
+
+int mbedcrypto_platform_set_calloc_free( void * (*calloc_func)( size_t, size_t ),
+ void (*free_func)( void * ) )
+{
+ mbedcrypto_calloc = calloc_func;
+ mbedcrypto_free = free_func;
+ return( 0 );
+}
+#endif /* MBEDCRYPTO_PLATFORM_MEMORY */
+
+#if defined(_WIN32)
+#include <stdarg.h>
+int mbedcrypto_platform_win32_snprintf( char *s, size_t n, const char *fmt, ... )
+{
+ int ret;
+ va_list argp;
+
+ /* Avoid calling the invalid parameter handler by checking ourselves */
+ if( s == NULL || n == 0 || fmt == NULL )
+ return( -1 );
+
+ va_start( argp, fmt );
+#if defined(_TRUNCATE) && !defined(__MINGW32__)
+ ret = _vsnprintf_s( s, n, _TRUNCATE, fmt, argp );
+#else
+ ret = _vsnprintf( s, n, fmt, argp );
+ if( ret < 0 || (size_t) ret == n )
+ {
+ s[n-1] = '\0';
+ ret = -1;
+ }
+#endif
+ va_end( argp );
+
+ return( ret );
+}
+#endif
+
+#if defined(MBEDCRYPTO_PLATFORM_SNPRINTF_ALT)
+#if !defined(MBEDCRYPTO_PLATFORM_STD_SNPRINTF)
+/*
+ * Make dummy function to prevent NULL pointer dereferences
+ */
+static int platform_snprintf_uninit( char * s, size_t n,
+ const char * format, ... )
+{
+ ((void) s);
+ ((void) n);
+ ((void) format);
+ return( 0 );
+}
+
+#define MBEDCRYPTO_PLATFORM_STD_SNPRINTF platform_snprintf_uninit
+#endif /* !MBEDCRYPTO_PLATFORM_STD_SNPRINTF */
+
+int (*mbedcrypto_snprintf)( char * s, size_t n,
+ const char * format,
+ ... ) = MBEDCRYPTO_PLATFORM_STD_SNPRINTF;
+
+int mbedcrypto_platform_set_snprintf( int (*snprintf_func)( char * s, size_t n,
+ const char * format,
+ ... ) )
+{
+ mbedcrypto_snprintf = snprintf_func;
+ return( 0 );
+}
+#endif /* MBEDCRYPTO_PLATFORM_SNPRINTF_ALT */
+
+#if defined(MBEDCRYPTO_PLATFORM_PRINTF_ALT)
+#if !defined(MBEDCRYPTO_PLATFORM_STD_PRINTF)
+/*
+ * Make dummy function to prevent NULL pointer dereferences
+ */
+static int platform_printf_uninit( const char *format, ... )
+{
+ ((void) format);
+ return( 0 );
+}
+
+#define MBEDCRYPTO_PLATFORM_STD_PRINTF platform_printf_uninit
+#endif /* !MBEDCRYPTO_PLATFORM_STD_PRINTF */
+
+int (*mbedcrypto_printf)( const char *, ... ) = MBEDCRYPTO_PLATFORM_STD_PRINTF;
+
+int mbedcrypto_platform_set_printf( int (*printf_func)( const char *, ... ) )
+{
+ mbedcrypto_printf = printf_func;
+ return( 0 );
+}
+#endif /* MBEDCRYPTO_PLATFORM_PRINTF_ALT */
+
+#if defined(MBEDCRYPTO_PLATFORM_FPRINTF_ALT)
+#if !defined(MBEDCRYPTO_PLATFORM_STD_FPRINTF)
+/*
+ * Make dummy function to prevent NULL pointer dereferences
+ */
+static int platform_fprintf_uninit( FILE *stream, const char *format, ... )
+{
+ ((void) stream);
+ ((void) format);
+ return( 0 );
+}
+
+#define MBEDCRYPTO_PLATFORM_STD_FPRINTF platform_fprintf_uninit
+#endif /* !MBEDCRYPTO_PLATFORM_STD_FPRINTF */
+
+int (*mbedcrypto_fprintf)( FILE *, const char *, ... ) =
+ MBEDCRYPTO_PLATFORM_STD_FPRINTF;
+
+int mbedcrypto_platform_set_fprintf( int (*fprintf_func)( FILE *, const char *, ... ) )
+{
+ mbedcrypto_fprintf = fprintf_func;
+ return( 0 );
+}
+#endif /* MBEDCRYPTO_PLATFORM_FPRINTF_ALT */
+
+#if defined(MBEDCRYPTO_PLATFORM_EXIT_ALT)
+#if !defined(MBEDCRYPTO_PLATFORM_STD_EXIT)
+/*
+ * Make dummy function to prevent NULL pointer dereferences
+ */
+static void platform_exit_uninit( int status )
+{
+ ((void) status);
+}
+
+#define MBEDCRYPTO_PLATFORM_STD_EXIT platform_exit_uninit
+#endif /* !MBEDCRYPTO_PLATFORM_STD_EXIT */
+
+void (*mbedcrypto_exit)( int status ) = MBEDCRYPTO_PLATFORM_STD_EXIT;
+
+int mbedcrypto_platform_set_exit( void (*exit_func)( int status ) )
+{
+ mbedcrypto_exit = exit_func;
+ return( 0 );
+}
+#endif /* MBEDCRYPTO_PLATFORM_EXIT_ALT */
+
+#if defined(MBEDCRYPTO_HAVE_TIME)
+
+#if defined(MBEDCRYPTO_PLATFORM_TIME_ALT)
+#if !defined(MBEDCRYPTO_PLATFORM_STD_TIME)
+/*
+ * Make dummy function to prevent NULL pointer dereferences
+ */
+static mbedcrypto_time_t platform_time_uninit( mbedcrypto_time_t* timer )
+{
+ ((void) timer);
+ return( 0 );
+}
+
+#define MBEDCRYPTO_PLATFORM_STD_TIME platform_time_uninit
+#endif /* !MBEDCRYPTO_PLATFORM_STD_TIME */
+
+mbedcrypto_time_t (*mbedcrypto_time)( mbedcrypto_time_t* timer ) = MBEDCRYPTO_PLATFORM_STD_TIME;
+
+int mbedcrypto_platform_set_time( mbedcrypto_time_t (*time_func)( mbedcrypto_time_t* timer ) )
+{
+ mbedcrypto_time = time_func;
+ return( 0 );
+}
+#endif /* MBEDCRYPTO_PLATFORM_TIME_ALT */
+
+#endif /* MBEDCRYPTO_HAVE_TIME */
+
+#if defined(MBEDCRYPTO_ENTROPY_NV_SEED)
+#if !defined(MBEDCRYPTO_PLATFORM_NO_STD_FUNCTIONS) && defined(MBEDCRYPTO_FS_IO)
+/* Default implementations for the platform independent seed functions use
+ * standard libc file functions to read from and write to a pre-defined filename
+ */
+int mbedcrypto_platform_std_nv_seed_read( unsigned char *buf, size_t buf_len )
+{
+ FILE *file;
+ size_t n;
+
+ if( ( file = fopen( MBEDCRYPTO_PLATFORM_STD_NV_SEED_FILE, "rb" ) ) == NULL )
+ return( -1 );
+
+ if( ( n = fread( buf, 1, buf_len, file ) ) != buf_len )
+ {
+ fclose( file );
+ mbedcrypto_platform_zeroize( buf, buf_len );
+ return( -1 );
+ }
+
+ fclose( file );
+ return( (int)n );
+}
+
+int mbedcrypto_platform_std_nv_seed_write( unsigned char *buf, size_t buf_len )
+{
+ FILE *file;
+ size_t n;
+
+ if( ( file = fopen( MBEDCRYPTO_PLATFORM_STD_NV_SEED_FILE, "w" ) ) == NULL )
+ return -1;
+
+ if( ( n = fwrite( buf, 1, buf_len, file ) ) != buf_len )
+ {
+ fclose( file );
+ return -1;
+ }
+
+ fclose( file );
+ return( (int)n );
+}
+#endif /* MBEDCRYPTO_PLATFORM_NO_STD_FUNCTIONS */
+
+#if defined(MBEDCRYPTO_PLATFORM_NV_SEED_ALT)
+#if !defined(MBEDCRYPTO_PLATFORM_STD_NV_SEED_READ)
+/*
+ * Make dummy function to prevent NULL pointer dereferences
+ */
+static int platform_nv_seed_read_uninit( unsigned char *buf, size_t buf_len )
+{
+ ((void) buf);
+ ((void) buf_len);
+ return( -1 );
+}
+
+#define MBEDCRYPTO_PLATFORM_STD_NV_SEED_READ platform_nv_seed_read_uninit
+#endif /* !MBEDCRYPTO_PLATFORM_STD_NV_SEED_READ */
+
+#if !defined(MBEDCRYPTO_PLATFORM_STD_NV_SEED_WRITE)
+/*
+ * Make dummy function to prevent NULL pointer dereferences
+ */
+static int platform_nv_seed_write_uninit( unsigned char *buf, size_t buf_len )
+{
+ ((void) buf);
+ ((void) buf_len);
+ return( -1 );
+}
+
+#define MBEDCRYPTO_PLATFORM_STD_NV_SEED_WRITE platform_nv_seed_write_uninit
+#endif /* !MBEDCRYPTO_PLATFORM_STD_NV_SEED_WRITE */
+
+int (*mbedcrypto_nv_seed_read)( unsigned char *buf, size_t buf_len ) =
+ MBEDCRYPTO_PLATFORM_STD_NV_SEED_READ;
+int (*mbedcrypto_nv_seed_write)( unsigned char *buf, size_t buf_len ) =
+ MBEDCRYPTO_PLATFORM_STD_NV_SEED_WRITE;
+
+int mbedcrypto_platform_set_nv_seed(
+ int (*nv_seed_read_func)( unsigned char *buf, size_t buf_len ),
+ int (*nv_seed_write_func)( unsigned char *buf, size_t buf_len ) )
+{
+ mbedcrypto_nv_seed_read = nv_seed_read_func;
+ mbedcrypto_nv_seed_write = nv_seed_write_func;
+ return( 0 );
+}
+#endif /* MBEDCRYPTO_PLATFORM_NV_SEED_ALT */
+#endif /* MBEDCRYPTO_ENTROPY_NV_SEED */
+
+#if !defined(MBEDCRYPTO_PLATFORM_SETUP_TEARDOWN_ALT)
+/*
+ * Placeholder platform setup that does nothing by default
+ */
+int mbedcrypto_platform_setup( mbedcrypto_platform_context *ctx )
+{
+ (void)ctx;
+
+ return( 0 );
+}
+
+/*
+ * Placeholder platform teardown that does nothing by default
+ */
+void mbedcrypto_platform_teardown( mbedcrypto_platform_context *ctx )
+{
+ (void)ctx;
+}
+#endif /* MBEDCRYPTO_PLATFORM_SETUP_TEARDOWN_ALT */
+
+#endif /* MBEDCRYPTO_PLATFORM_C */
diff --git a/library/platform_util.c b/library/platform_util.c
new file mode 100644
index 0000000..28ea881
--- /dev/null
+++ b/library/platform_util.c
@@ -0,0 +1,67 @@
+/*
+ * Common and shared functions used by multiple modules in the Mbed Crypto
+ * library.
+ *
+ * Copyright (C) 2018, 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 Crypto (https://tls.mbed.org)
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#include "mbedcrypto/platform_util.h"
+
+#include <stddef.h>
+#include <string.h>
+
+#if !defined(MBEDCRYPTO_PLATFORM_ZEROIZE_ALT)
+/*
+ * This implementation should never be optimized out by the compiler
+ *
+ * This implementation for mbedcrypto_platform_zeroize() was inspired from Colin
+ * Percival's blog article at:
+ *
+ * http://www.daemonology.net/blog/2014-09-04-how-to-zero-a-buffer.html
+ *
+ * It uses a volatile function pointer to the standard memset(). Because the
+ * pointer is volatile the compiler expects it to change at
+ * any time and will not optimize out the call that could potentially perform
+ * other operations on the input buffer instead of just setting it to 0.
+ * Nevertheless, as pointed out by davidtgoldblatt on Hacker News
+ * (refer to http://www.daemonology.net/blog/2014-09-05-erratum.html for
+ * details), optimizations of the following form are still possible:
+ *
+ * if( memset_func != memset )
+ * memset_func( buf, 0, len );
+ *
+ * Note that it is extremely difficult to guarantee that
+ * mbedcrypto_platform_zeroize() will not be optimized out by aggressive compilers
+ * in a portable way. For this reason, Mbed Crypto also provides the configuration
+ * option MBEDCRYPTO_PLATFORM_ZEROIZE_ALT, which allows users to configure
+ * mbedcrypto_platform_zeroize() to use a suitable implementation for their
+ * platform and needs.
+ */
+static void * (* const volatile memset_func)( void *, int, size_t ) = memset;
+
+void mbedcrypto_platform_zeroize( void *buf, size_t len )
+{
+ memset_func( buf, 0, len );
+}
+#endif /* MBEDCRYPTO_PLATFORM_ZEROIZE_ALT */
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
new file mode 100644
index 0000000..4408b45
--- /dev/null
+++ b/library/psa_crypto.c
@@ -0,0 +1,3513 @@
+/*
+ * PSA crypto layer on top of Mbed Crypto crypto
+ */
+/* Copyright (C) 2018, 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 Crypto (https://tls.mbed.org)
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_PSA_CRYPTO_C)
+/*
+ * In case MBEDCRYPTO_PSA_CRYPTO_SPM is defined the code is built for SPM (Secure
+ * Partition Manager) integration which separate the code into two parts
+ * NSPE (Non-Secure Process Environment) and SPE (Secure Process Environment).
+ * In this mode an additional header file should be included.
+ */
+#if defined(MBEDCRYPTO_PSA_CRYPTO_SPM)
+/*
+ * PSA_CRYPTO_SECURE means that this file is compiled to the SPE side.
+ * some headers will be affected by this flag.
+ */
+#define PSA_CRYPTO_SECURE 1
+#include "crypto_spe.h"
+#endif
+
+#include "psa/crypto.h"
+
+#include <stdlib.h>
+#include <string.h>
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#define mbedcrypto_calloc calloc
+#define mbedcrypto_free free
+#endif
+
+#include "mbedcrypto/arc4.h"
+#include "mbedcrypto/asn1.h"
+#include "mbedcrypto/bignum.h"
+#include "mbedcrypto/blowfish.h"
+#include "mbedcrypto/camellia.h"
+#include "mbedcrypto/cipher.h"
+#include "mbedcrypto/ccm.h"
+#include "mbedcrypto/cmac.h"
+#include "mbedcrypto/ctr_drbg.h"
+#include "mbedcrypto/des.h"
+#include "mbedcrypto/ecp.h"
+#include "mbedcrypto/entropy.h"
+#include "mbedcrypto/error.h"
+#include "mbedcrypto/gcm.h"
+#include "mbedcrypto/md2.h"
+#include "mbedcrypto/md4.h"
+#include "mbedcrypto/md5.h"
+#include "mbedcrypto/md.h"
+#include "mbedcrypto/md_internal.h"
+#include "mbedcrypto/pk.h"
+#include "mbedcrypto/pk_internal.h"
+#include "mbedcrypto/ripemd160.h"
+#include "mbedcrypto/rsa.h"
+#include "mbedcrypto/sha1.h"
+#include "mbedcrypto/sha256.h"
+#include "mbedcrypto/sha512.h"
+#include "mbedcrypto/xtea.h"
+
+
+
+#define ARRAY_LENGTH( array ) ( sizeof( array ) / sizeof( *( array ) ) )
+
+/* Implementation that should never be optimized out by the compiler */
+static void mbedcrypto_zeroize( void *v, size_t n )
+{
+ volatile unsigned char *p = v; while( n-- ) *p++ = 0;
+}
+
+/* constant-time buffer comparison */
+static inline int safer_memcmp( const uint8_t *a, const uint8_t *b, size_t n )
+{
+ size_t i;
+ unsigned char diff = 0;
+
+ for( i = 0; i < n; i++ )
+ diff |= a[i] ^ b[i];
+
+ return( diff );
+}
+
+
+
+/****************************************************************/
+/* Global data, support functions and library management */
+/****************************************************************/
+
+/* Number of key slots (plus one because 0 is not used).
+ * The value is a compile-time constant for now, for simplicity. */
+#define PSA_KEY_SLOT_COUNT 32
+
+typedef struct
+{
+ psa_key_type_t type;
+ psa_key_policy_t policy;
+ psa_key_lifetime_t lifetime;
+ union
+ {
+ struct raw_data
+ {
+ uint8_t *data;
+ size_t bytes;
+ } raw;
+#if defined(MBEDCRYPTO_RSA_C)
+ mbedcrypto_rsa_context *rsa;
+#endif /* MBEDCRYPTO_RSA_C */
+#if defined(MBEDCRYPTO_ECP_C)
+ mbedcrypto_ecp_keypair *ecp;
+#endif /* MBEDCRYPTO_ECP_C */
+ } data;
+} key_slot_t;
+
+static int key_type_is_raw_bytes( psa_key_type_t type )
+{
+ psa_key_type_t category = type & PSA_KEY_TYPE_CATEGORY_MASK;
+ return( category == PSA_KEY_TYPE_RAW_DATA ||
+ category == PSA_KEY_TYPE_CATEGORY_SYMMETRIC );
+}
+
+typedef struct
+{
+ int initialized;
+ mbedcrypto_entropy_context entropy;
+ mbedcrypto_ctr_drbg_context ctr_drbg;
+ key_slot_t key_slots[PSA_KEY_SLOT_COUNT];
+} psa_global_data_t;
+
+static psa_global_data_t global_data;
+
+static psa_status_t mbedcrypto_to_psa_error( int ret )
+{
+ /* If there's both a high-level code and low-level code, dispatch on
+ * the high-level code. */
+ switch( ret < -0x7f ? - ( -ret & 0x7f80 ) : ret )
+ {
+ case 0:
+ return( PSA_SUCCESS );
+
+ case MBEDCRYPTO_ERR_AES_INVALID_KEY_LENGTH:
+ case MBEDCRYPTO_ERR_AES_INVALID_INPUT_LENGTH:
+ case MBEDCRYPTO_ERR_AES_FEATURE_UNAVAILABLE:
+ return( PSA_ERROR_NOT_SUPPORTED );
+ case MBEDCRYPTO_ERR_AES_HW_ACCEL_FAILED:
+ return( PSA_ERROR_HARDWARE_FAILURE );
+
+ case MBEDCRYPTO_ERR_ARC4_HW_ACCEL_FAILED:
+ return( PSA_ERROR_HARDWARE_FAILURE );
+
+ case MBEDCRYPTO_ERR_ASN1_OUT_OF_DATA:
+ case MBEDCRYPTO_ERR_ASN1_UNEXPECTED_TAG:
+ case MBEDCRYPTO_ERR_ASN1_INVALID_LENGTH:
+ case MBEDCRYPTO_ERR_ASN1_LENGTH_MISMATCH:
+ case MBEDCRYPTO_ERR_ASN1_INVALID_DATA:
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ case MBEDCRYPTO_ERR_ASN1_ALLOC_FAILED:
+ return( PSA_ERROR_INSUFFICIENT_MEMORY );
+ case MBEDCRYPTO_ERR_ASN1_BUF_TOO_SMALL:
+ return( PSA_ERROR_BUFFER_TOO_SMALL );
+
+ case MBEDCRYPTO_ERR_BLOWFISH_INVALID_KEY_LENGTH:
+ case MBEDCRYPTO_ERR_BLOWFISH_INVALID_INPUT_LENGTH:
+ return( PSA_ERROR_NOT_SUPPORTED );
+ case MBEDCRYPTO_ERR_BLOWFISH_HW_ACCEL_FAILED:
+ return( PSA_ERROR_HARDWARE_FAILURE );
+
+ case MBEDCRYPTO_ERR_CAMELLIA_INVALID_KEY_LENGTH:
+ case MBEDCRYPTO_ERR_CAMELLIA_INVALID_INPUT_LENGTH:
+ return( PSA_ERROR_NOT_SUPPORTED );
+ case MBEDCRYPTO_ERR_CAMELLIA_HW_ACCEL_FAILED:
+ return( PSA_ERROR_HARDWARE_FAILURE );
+
+ case MBEDCRYPTO_ERR_CCM_BAD_INPUT:
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ case MBEDCRYPTO_ERR_CCM_AUTH_FAILED:
+ return( PSA_ERROR_INVALID_SIGNATURE );
+ case MBEDCRYPTO_ERR_CCM_HW_ACCEL_FAILED:
+ return( PSA_ERROR_HARDWARE_FAILURE );
+
+ case MBEDCRYPTO_ERR_CIPHER_FEATURE_UNAVAILABLE:
+ return( PSA_ERROR_NOT_SUPPORTED );
+ case MBEDCRYPTO_ERR_CIPHER_BAD_INPUT_DATA:
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ case MBEDCRYPTO_ERR_CIPHER_ALLOC_FAILED:
+ return( PSA_ERROR_INSUFFICIENT_MEMORY );
+ case MBEDCRYPTO_ERR_CIPHER_INVALID_PADDING:
+ return( PSA_ERROR_INVALID_PADDING );
+ case MBEDCRYPTO_ERR_CIPHER_FULL_BLOCK_EXPECTED:
+ return( PSA_ERROR_BAD_STATE );
+ case MBEDCRYPTO_ERR_CIPHER_AUTH_FAILED:
+ return( PSA_ERROR_INVALID_SIGNATURE );
+ case MBEDCRYPTO_ERR_CIPHER_INVALID_CONTEXT:
+ return( PSA_ERROR_TAMPERING_DETECTED );
+ case MBEDCRYPTO_ERR_CIPHER_HW_ACCEL_FAILED:
+ return( PSA_ERROR_HARDWARE_FAILURE );
+
+ case MBEDCRYPTO_ERR_CMAC_HW_ACCEL_FAILED:
+ return( PSA_ERROR_HARDWARE_FAILURE );
+
+ case MBEDCRYPTO_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED:
+ return( PSA_ERROR_INSUFFICIENT_ENTROPY );
+ case MBEDCRYPTO_ERR_CTR_DRBG_REQUEST_TOO_BIG:
+ case MBEDCRYPTO_ERR_CTR_DRBG_INPUT_TOO_BIG:
+ return( PSA_ERROR_NOT_SUPPORTED );
+ case MBEDCRYPTO_ERR_CTR_DRBG_FILE_IO_ERROR:
+ return( PSA_ERROR_INSUFFICIENT_ENTROPY );
+
+ case MBEDCRYPTO_ERR_DES_INVALID_INPUT_LENGTH:
+ return( PSA_ERROR_NOT_SUPPORTED );
+ case MBEDCRYPTO_ERR_DES_HW_ACCEL_FAILED:
+ return( PSA_ERROR_HARDWARE_FAILURE );
+
+ case MBEDCRYPTO_ERR_ENTROPY_NO_SOURCES_DEFINED:
+ case MBEDCRYPTO_ERR_ENTROPY_NO_STRONG_SOURCE:
+ case MBEDCRYPTO_ERR_ENTROPY_SOURCE_FAILED:
+ return( PSA_ERROR_INSUFFICIENT_ENTROPY );
+
+ case MBEDCRYPTO_ERR_GCM_AUTH_FAILED:
+ return( PSA_ERROR_INVALID_SIGNATURE );
+ case MBEDCRYPTO_ERR_GCM_BAD_INPUT:
+ return( PSA_ERROR_NOT_SUPPORTED );
+ case MBEDCRYPTO_ERR_GCM_HW_ACCEL_FAILED:
+ return( PSA_ERROR_HARDWARE_FAILURE );
+
+ case MBEDCRYPTO_ERR_MD2_HW_ACCEL_FAILED:
+ case MBEDCRYPTO_ERR_MD4_HW_ACCEL_FAILED:
+ case MBEDCRYPTO_ERR_MD5_HW_ACCEL_FAILED:
+ return( PSA_ERROR_HARDWARE_FAILURE );
+
+ case MBEDCRYPTO_ERR_MD_FEATURE_UNAVAILABLE:
+ return( PSA_ERROR_NOT_SUPPORTED );
+ case MBEDCRYPTO_ERR_MD_BAD_INPUT_DATA:
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ case MBEDCRYPTO_ERR_MD_ALLOC_FAILED:
+ return( PSA_ERROR_INSUFFICIENT_MEMORY );
+ case MBEDCRYPTO_ERR_MD_FILE_IO_ERROR:
+ return( PSA_ERROR_STORAGE_FAILURE );
+ case MBEDCRYPTO_ERR_MD_HW_ACCEL_FAILED:
+ return( PSA_ERROR_HARDWARE_FAILURE );
+
+ case MBEDCRYPTO_ERR_PK_ALLOC_FAILED:
+ return( PSA_ERROR_INSUFFICIENT_MEMORY );
+ case MBEDCRYPTO_ERR_PK_TYPE_MISMATCH:
+ case MBEDCRYPTO_ERR_PK_BAD_INPUT_DATA:
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ case MBEDCRYPTO_ERR_PK_FILE_IO_ERROR:
+ return( PSA_ERROR_STORAGE_FAILURE );
+ case MBEDCRYPTO_ERR_PK_KEY_INVALID_VERSION:
+ case MBEDCRYPTO_ERR_PK_KEY_INVALID_FORMAT:
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ case MBEDCRYPTO_ERR_PK_UNKNOWN_PK_ALG:
+ return( PSA_ERROR_NOT_SUPPORTED );
+ case MBEDCRYPTO_ERR_PK_PASSWORD_REQUIRED:
+ case MBEDCRYPTO_ERR_PK_PASSWORD_MISMATCH:
+ return( PSA_ERROR_NOT_PERMITTED );
+ case MBEDCRYPTO_ERR_PK_INVALID_PUBKEY:
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ case MBEDCRYPTO_ERR_PK_INVALID_ALG:
+ case MBEDCRYPTO_ERR_PK_UNKNOWN_NAMED_CURVE:
+ case MBEDCRYPTO_ERR_PK_FEATURE_UNAVAILABLE:
+ return( PSA_ERROR_NOT_SUPPORTED );
+ case MBEDCRYPTO_ERR_PK_SIG_LEN_MISMATCH:
+ return( PSA_ERROR_INVALID_SIGNATURE );
+ case MBEDCRYPTO_ERR_PK_HW_ACCEL_FAILED:
+ return( PSA_ERROR_HARDWARE_FAILURE );
+
+ case MBEDCRYPTO_ERR_RIPEMD160_HW_ACCEL_FAILED:
+ return( PSA_ERROR_HARDWARE_FAILURE );
+
+ case MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA:
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ case MBEDCRYPTO_ERR_RSA_INVALID_PADDING:
+ return( PSA_ERROR_INVALID_PADDING );
+ case MBEDCRYPTO_ERR_RSA_KEY_GEN_FAILED:
+ return( PSA_ERROR_HARDWARE_FAILURE );
+ case MBEDCRYPTO_ERR_RSA_KEY_CHECK_FAILED:
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ case MBEDCRYPTO_ERR_RSA_PUBLIC_FAILED:
+ case MBEDCRYPTO_ERR_RSA_PRIVATE_FAILED:
+ return( PSA_ERROR_TAMPERING_DETECTED );
+ case MBEDCRYPTO_ERR_RSA_VERIFY_FAILED:
+ return( PSA_ERROR_INVALID_SIGNATURE );
+ case MBEDCRYPTO_ERR_RSA_OUTPUT_TOO_LARGE:
+ return( PSA_ERROR_BUFFER_TOO_SMALL );
+ case MBEDCRYPTO_ERR_RSA_RNG_FAILED:
+ return( PSA_ERROR_INSUFFICIENT_MEMORY );
+ case MBEDCRYPTO_ERR_RSA_UNSUPPORTED_OPERATION:
+ return( PSA_ERROR_NOT_SUPPORTED );
+ case MBEDCRYPTO_ERR_RSA_HW_ACCEL_FAILED:
+ return( PSA_ERROR_HARDWARE_FAILURE );
+
+ case MBEDCRYPTO_ERR_SHA1_HW_ACCEL_FAILED:
+ case MBEDCRYPTO_ERR_SHA256_HW_ACCEL_FAILED:
+ case MBEDCRYPTO_ERR_SHA512_HW_ACCEL_FAILED:
+ return( PSA_ERROR_HARDWARE_FAILURE );
+
+ case MBEDCRYPTO_ERR_XTEA_INVALID_INPUT_LENGTH:
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ case MBEDCRYPTO_ERR_XTEA_HW_ACCEL_FAILED:
+ return( PSA_ERROR_HARDWARE_FAILURE );
+
+ case MBEDCRYPTO_ERR_ECP_BAD_INPUT_DATA:
+ case MBEDCRYPTO_ERR_ECP_INVALID_KEY:
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ case MBEDCRYPTO_ERR_ECP_BUFFER_TOO_SMALL:
+ return( PSA_ERROR_BUFFER_TOO_SMALL );
+ case MBEDCRYPTO_ERR_ECP_FEATURE_UNAVAILABLE:
+ return( PSA_ERROR_NOT_SUPPORTED );
+ case MBEDCRYPTO_ERR_ECP_SIG_LEN_MISMATCH:
+ case MBEDCRYPTO_ERR_ECP_VERIFY_FAILED:
+ return( PSA_ERROR_INVALID_SIGNATURE );
+ case MBEDCRYPTO_ERR_ECP_ALLOC_FAILED:
+ return( PSA_ERROR_INSUFFICIENT_MEMORY );
+ case MBEDCRYPTO_ERR_ECP_HW_ACCEL_FAILED:
+ return( PSA_ERROR_HARDWARE_FAILURE );
+
+ default:
+ return( PSA_ERROR_UNKNOWN_ERROR );
+ }
+}
+
+/* Retrieve a key slot, occupied or not. */
+static psa_status_t psa_get_key_slot( psa_key_slot_t key,
+ key_slot_t **p_slot )
+{
+ /* 0 is not a valid slot number under any circumstance. This
+ * implementation provides slots number 1 to N where N is the
+ * number of available slots. */
+ if( key == 0 || key > ARRAY_LENGTH( global_data.key_slots ) )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+
+ *p_slot = &global_data.key_slots[key - 1];
+ return( PSA_SUCCESS );
+}
+
+/* Retrieve an empty key slot (slot with no key data, but possibly
+ * with some metadata such as a policy). */
+static psa_status_t psa_get_empty_key_slot( psa_key_slot_t key,
+ key_slot_t **p_slot )
+{
+ psa_status_t status;
+ key_slot_t *slot = NULL;
+
+ *p_slot = NULL;
+
+ status = psa_get_key_slot( key, &slot );
+ if( status != PSA_SUCCESS )
+ return( status );
+
+ if( slot->type != PSA_KEY_TYPE_NONE )
+ return( PSA_ERROR_OCCUPIED_SLOT );
+
+ *p_slot = slot;
+ return( status );
+}
+
+/** Retrieve a slot which must contain a key. The key must have allow all the
+ * usage flags set in \p usage. If \p alg is nonzero, the key must allow
+ * operations with this algorithm. */
+static psa_status_t psa_get_key_from_slot( psa_key_slot_t key,
+ key_slot_t **p_slot,
+ psa_key_usage_t usage,
+ psa_algorithm_t alg )
+{
+ psa_status_t status;
+ key_slot_t *slot = NULL;
+
+ *p_slot = NULL;
+
+ status = psa_get_key_slot( key, &slot );
+ if( status != PSA_SUCCESS )
+ return( status );
+ if( slot->type == PSA_KEY_TYPE_NONE )
+ return( PSA_ERROR_EMPTY_SLOT );
+
+ /* Enforce that usage policy for the key slot contains all the flags
+ * required by the usage parameter. There is one exception: public
+ * keys can always be exported, so we treat public key objects as
+ * if they had the export flag. */
+ if( PSA_KEY_TYPE_IS_PUBLIC_KEY( slot->type ) )
+ usage &= ~PSA_KEY_USAGE_EXPORT;
+ if( ( slot->policy.usage & usage ) != usage )
+ return( PSA_ERROR_NOT_PERMITTED );
+ if( alg != 0 && ( alg != slot->policy.alg ) )
+ return( PSA_ERROR_NOT_PERMITTED );
+
+ *p_slot = slot;
+ return( PSA_SUCCESS );
+}
+
+
+
+/****************************************************************/
+/* Key management */
+/****************************************************************/
+
+#if defined(MBEDCRYPTO_ECP_C)
+static psa_ecc_curve_t mbedcrypto_ecc_group_to_psa( mbedcrypto_ecp_group_id grpid )
+{
+ switch( grpid )
+ {
+ case MBEDCRYPTO_ECP_DP_SECP192R1:
+ return( PSA_ECC_CURVE_SECP192R1 );
+ case MBEDCRYPTO_ECP_DP_SECP224R1:
+ return( PSA_ECC_CURVE_SECP224R1 );
+ case MBEDCRYPTO_ECP_DP_SECP256R1:
+ return( PSA_ECC_CURVE_SECP256R1 );
+ case MBEDCRYPTO_ECP_DP_SECP384R1:
+ return( PSA_ECC_CURVE_SECP384R1 );
+ case MBEDCRYPTO_ECP_DP_SECP521R1:
+ return( PSA_ECC_CURVE_SECP521R1 );
+ case MBEDCRYPTO_ECP_DP_BP256R1:
+ return( PSA_ECC_CURVE_BRAINPOOL_P256R1 );
+ case MBEDCRYPTO_ECP_DP_BP384R1:
+ return( PSA_ECC_CURVE_BRAINPOOL_P384R1 );
+ case MBEDCRYPTO_ECP_DP_BP512R1:
+ return( PSA_ECC_CURVE_BRAINPOOL_P512R1 );
+ case MBEDCRYPTO_ECP_DP_CURVE25519:
+ return( PSA_ECC_CURVE_CURVE25519 );
+ case MBEDCRYPTO_ECP_DP_SECP192K1:
+ return( PSA_ECC_CURVE_SECP192K1 );
+ case MBEDCRYPTO_ECP_DP_SECP224K1:
+ return( PSA_ECC_CURVE_SECP224K1 );
+ case MBEDCRYPTO_ECP_DP_SECP256K1:
+ return( PSA_ECC_CURVE_SECP256K1 );
+ case MBEDCRYPTO_ECP_DP_CURVE448:
+ return( PSA_ECC_CURVE_CURVE448 );
+ default:
+ return( 0 );
+ }
+}
+
+static mbedcrypto_ecp_group_id mbedcrypto_ecc_group_of_psa( psa_ecc_curve_t curve )
+{
+ switch( curve )
+ {
+ case PSA_ECC_CURVE_SECP192R1:
+ return( MBEDCRYPTO_ECP_DP_SECP192R1 );
+ case PSA_ECC_CURVE_SECP224R1:
+ return( MBEDCRYPTO_ECP_DP_SECP224R1 );
+ case PSA_ECC_CURVE_SECP256R1:
+ return( MBEDCRYPTO_ECP_DP_SECP256R1 );
+ case PSA_ECC_CURVE_SECP384R1:
+ return( MBEDCRYPTO_ECP_DP_SECP384R1 );
+ case PSA_ECC_CURVE_SECP521R1:
+ return( MBEDCRYPTO_ECP_DP_SECP521R1 );
+ case PSA_ECC_CURVE_BRAINPOOL_P256R1:
+ return( MBEDCRYPTO_ECP_DP_BP256R1 );
+ case PSA_ECC_CURVE_BRAINPOOL_P384R1:
+ return( MBEDCRYPTO_ECP_DP_BP384R1 );
+ case PSA_ECC_CURVE_BRAINPOOL_P512R1:
+ return( MBEDCRYPTO_ECP_DP_BP512R1 );
+ case PSA_ECC_CURVE_CURVE25519:
+ return( MBEDCRYPTO_ECP_DP_CURVE25519 );
+ case PSA_ECC_CURVE_SECP192K1:
+ return( MBEDCRYPTO_ECP_DP_SECP192K1 );
+ case PSA_ECC_CURVE_SECP224K1:
+ return( MBEDCRYPTO_ECP_DP_SECP224K1 );
+ case PSA_ECC_CURVE_SECP256K1:
+ return( MBEDCRYPTO_ECP_DP_SECP256K1 );
+ case PSA_ECC_CURVE_CURVE448:
+ return( MBEDCRYPTO_ECP_DP_CURVE448 );
+ default:
+ return( MBEDCRYPTO_ECP_DP_NONE );
+ }
+}
+#endif /* defined(MBEDCRYPTO_ECP_C) */
+
+static psa_status_t prepare_raw_data_slot( psa_key_type_t type,
+ size_t bits,
+ struct raw_data *raw )
+{
+ /* Check that the bit size is acceptable for the key type */
+ switch( type )
+ {
+ case PSA_KEY_TYPE_RAW_DATA:
+ if( bits == 0 )
+ {
+ raw->bytes = 0;
+ raw->data = NULL;
+ return( PSA_SUCCESS );
+ }
+ break;
+#if defined(MBEDCRYPTO_MD_C)
+ case PSA_KEY_TYPE_HMAC:
+#endif
+ case PSA_KEY_TYPE_DERIVE:
+ break;
+#if defined(MBEDCRYPTO_AES_C)
+ case PSA_KEY_TYPE_AES:
+ if( bits != 128 && bits != 192 && bits != 256 )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ break;
+#endif
+#if defined(MBEDCRYPTO_CAMELLIA_C)
+ case PSA_KEY_TYPE_CAMELLIA:
+ if( bits != 128 && bits != 192 && bits != 256 )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ break;
+#endif
+#if defined(MBEDCRYPTO_DES_C)
+ case PSA_KEY_TYPE_DES:
+ if( bits != 64 && bits != 128 && bits != 192 )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ break;
+#endif
+#if defined(MBEDCRYPTO_ARC4_C)
+ case PSA_KEY_TYPE_ARC4:
+ if( bits < 8 || bits > 2048 )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ break;
+#endif
+ default:
+ return( PSA_ERROR_NOT_SUPPORTED );
+ }
+ if( bits % 8 != 0 )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+
+ /* Allocate memory for the key */
+ raw->bytes = PSA_BITS_TO_BYTES( bits );
+ raw->data = mbedcrypto_calloc( 1, raw->bytes );
+ if( raw->data == NULL )
+ {
+ raw->bytes = 0;
+ return( PSA_ERROR_INSUFFICIENT_MEMORY );
+ }
+ return( PSA_SUCCESS );
+}
+
+#if defined(MBEDCRYPTO_RSA_C) && defined(MBEDCRYPTO_PK_PARSE_C)
+static psa_status_t psa_import_rsa_key( mbedcrypto_pk_context *pk,
+ mbedcrypto_rsa_context **p_rsa )
+{
+ if( mbedcrypto_pk_get_type( pk ) != MBEDCRYPTO_PK_RSA )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ else
+ {
+ mbedcrypto_rsa_context *rsa = mbedcrypto_pk_rsa( *pk );
+ size_t bits = mbedcrypto_rsa_get_bitlen( rsa );
+ if( bits > PSA_VENDOR_RSA_MAX_KEY_BITS )
+ return( PSA_ERROR_NOT_SUPPORTED );
+ *p_rsa = rsa;
+ return( PSA_SUCCESS );
+ }
+}
+#endif /* defined(MBEDCRYPTO_RSA_C) && defined(MBEDCRYPTO_PK_PARSE_C) */
+
+#if defined(MBEDCRYPTO_ECP_C) && defined(MBEDCRYPTO_PK_PARSE_C)
+static psa_status_t psa_import_ecp_key( psa_ecc_curve_t expected_curve,
+ mbedcrypto_pk_context *pk,
+ mbedcrypto_ecp_keypair **p_ecp )
+{
+ if( mbedcrypto_pk_get_type( pk ) != MBEDCRYPTO_PK_ECKEY )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ else
+ {
+ mbedcrypto_ecp_keypair *ecp = mbedcrypto_pk_ec( *pk );
+ psa_ecc_curve_t actual_curve = mbedcrypto_ecc_group_to_psa( ecp->grp.id );
+ if( actual_curve != expected_curve )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ *p_ecp = ecp;
+ return( PSA_SUCCESS );
+ }
+}
+#endif /* defined(MBEDCRYPTO_ECP_C) && defined(MBEDCRYPTO_PK_PARSE_C) */
+
+psa_status_t psa_import_key( psa_key_slot_t key,
+ psa_key_type_t type,
+ const uint8_t *data,
+ size_t data_length )
+{
+ key_slot_t *slot;
+ psa_status_t status = PSA_SUCCESS;
+ status = psa_get_empty_key_slot( key, &slot );
+ if( status != PSA_SUCCESS )
+ return( status );
+
+ if( key_type_is_raw_bytes( type ) )
+ {
+ /* Ensure that a bytes-to-bit conversion won't overflow. */
+ if( data_length > SIZE_MAX / 8 )
+ return( PSA_ERROR_NOT_SUPPORTED );
+ status = prepare_raw_data_slot( type,
+ PSA_BYTES_TO_BITS( data_length ),
+ &slot->data.raw );
+ if( status != PSA_SUCCESS )
+ return( status );
+ if( data_length != 0 )
+ memcpy( slot->data.raw.data, data, data_length );
+ }
+ else
+#if defined(MBEDCRYPTO_PK_PARSE_C)
+ if( PSA_KEY_TYPE_IS_RSA( type ) || PSA_KEY_TYPE_IS_ECC( type ) )
+ {
+ int ret;
+ mbedcrypto_pk_context pk;
+ mbedcrypto_pk_init( &pk );
+
+ /* Parse the data. */
+ if( PSA_KEY_TYPE_IS_KEYPAIR( type ) )
+ ret = mbedcrypto_pk_parse_key( &pk, data, data_length, NULL, 0 );
+ else
+ ret = mbedcrypto_pk_parse_public_key( &pk, data, data_length );
+ if( ret != 0 )
+ return( mbedcrypto_to_psa_error( ret ) );
+
+ /* We have something that the pkparse module recognizes.
+ * If it has the expected type and passes any type-specific
+ * checks, store it. */
+#if defined(MBEDCRYPTO_RSA_C)
+ if( PSA_KEY_TYPE_IS_RSA( type ) )
+ status = psa_import_rsa_key( &pk, &slot->data.rsa );
+ else
+#endif /* MBEDCRYPTO_RSA_C */
+#if defined(MBEDCRYPTO_ECP_C)
+ if( PSA_KEY_TYPE_IS_ECC( type ) )
+ status = psa_import_ecp_key( PSA_KEY_TYPE_GET_CURVE( type ),
+ &pk, &slot->data.ecp );
+ else
+#endif /* MBEDCRYPTO_ECP_C */
+ {
+ status = PSA_ERROR_NOT_SUPPORTED;
+ }
+
+ /* Free the content of the pk object only on error. On success,
+ * the content of the object has been stored in the slot. */
+ if( status != PSA_SUCCESS )
+ {
+ mbedcrypto_pk_free( &pk );
+ return( status );
+ }
+ }
+ else
+#endif /* defined(MBEDCRYPTO_PK_PARSE_C) */
+ {
+ return( PSA_ERROR_NOT_SUPPORTED );
+ }
+
+ slot->type = type;
+ return( PSA_SUCCESS );
+}
+
+psa_status_t psa_destroy_key( psa_key_slot_t key )
+{
+ key_slot_t *slot;
+ psa_status_t status;
+
+ status = psa_get_key_slot( key, &slot );
+ if( status != PSA_SUCCESS )
+ return( status );
+
+ if( slot->type == PSA_KEY_TYPE_NONE )
+ {
+ /* No key material to clean, but do zeroize the slot below to wipe
+ * metadata such as policies. */
+ }
+ else if( key_type_is_raw_bytes( slot->type ) )
+ {
+ mbedcrypto_free( slot->data.raw.data );
+ }
+ else
+#if defined(MBEDCRYPTO_RSA_C)
+ if( PSA_KEY_TYPE_IS_RSA( slot->type ) )
+ {
+ mbedcrypto_rsa_free( slot->data.rsa );
+ mbedcrypto_free( slot->data.rsa );
+ }
+ else
+#endif /* defined(MBEDCRYPTO_RSA_C) */
+#if defined(MBEDCRYPTO_ECP_C)
+ if( PSA_KEY_TYPE_IS_ECC( slot->type ) )
+ {
+ mbedcrypto_ecp_keypair_free( slot->data.ecp );
+ mbedcrypto_free( slot->data.ecp );
+ }
+ else
+#endif /* defined(MBEDCRYPTO_ECP_C) */
+ {
+ /* Shouldn't happen: the key type is not any type that we
+ * put in. */
+ return( PSA_ERROR_TAMPERING_DETECTED );
+ }
+
+ mbedcrypto_zeroize( slot, sizeof( *slot ) );
+ return( PSA_SUCCESS );
+}
+
+/* Return the size of the key in the given slot, in bits. */
+static size_t psa_get_key_bits( const key_slot_t *slot )
+{
+ if( key_type_is_raw_bytes( slot->type ) )
+ return( slot->data.raw.bytes * 8 );
+#if defined(MBEDCRYPTO_RSA_C)
+ if( PSA_KEY_TYPE_IS_RSA( slot->type ) )
+ return( mbedcrypto_rsa_get_bitlen( slot->data.rsa ) );
+#endif /* defined(MBEDCRYPTO_RSA_C) */
+#if defined(MBEDCRYPTO_ECP_C)
+ if( PSA_KEY_TYPE_IS_ECC( slot->type ) )
+ return( slot->data.ecp->grp.pbits );
+#endif /* defined(MBEDCRYPTO_ECP_C) */
+ /* Shouldn't happen except on an empty slot. */
+ return( 0 );
+}
+
+psa_status_t psa_get_key_information( psa_key_slot_t key,
+ psa_key_type_t *type,
+ size_t *bits )
+{
+ key_slot_t *slot;
+ psa_status_t status;
+
+ if( type != NULL )
+ *type = 0;
+ if( bits != NULL )
+ *bits = 0;
+ status = psa_get_key_slot( key, &slot );
+ if( status != PSA_SUCCESS )
+ return( status );
+
+ if( slot->type == PSA_KEY_TYPE_NONE )
+ return( PSA_ERROR_EMPTY_SLOT );
+ if( type != NULL )
+ *type = slot->type;
+ if( bits != NULL )
+ *bits = psa_get_key_bits( slot );
+ return( PSA_SUCCESS );
+}
+
+static psa_status_t psa_internal_export_key( psa_key_slot_t key,
+ uint8_t *data,
+ size_t data_size,
+ size_t *data_length,
+ int export_public_key )
+{
+ key_slot_t *slot;
+ psa_status_t status;
+ /* Exporting a public key doesn't require a usage flag. If we're
+ * called by psa_export_public_key(), don't require the EXPORT flag.
+ * If we're called by psa_export_key(), do require the EXPORT flag;
+ * if the key turns out to be public key object, psa_get_key_from_slot()
+ * will ignore this flag. */
+ psa_key_usage_t usage = export_public_key ? 0 : PSA_KEY_USAGE_EXPORT;
+
+ /* Set the key to empty now, so that even when there are errors, we always
+ * set data_length to a value between 0 and data_size. On error, setting
+ * the key to empty is a good choice because an empty key representation is
+ * unlikely to be accepted anywhere. */
+ *data_length = 0;
+
+ status = psa_get_key_from_slot( key, &slot, usage, 0 );
+ if( status != PSA_SUCCESS )
+ return( status );
+ if( export_public_key && ! PSA_KEY_TYPE_IS_ASYMMETRIC( slot->type ) )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+
+ if( key_type_is_raw_bytes( slot->type ) )
+ {
+ if( slot->data.raw.bytes > data_size )
+ return( PSA_ERROR_BUFFER_TOO_SMALL );
+ if( slot->data.raw.bytes != 0 )
+ memcpy( data, slot->data.raw.data, slot->data.raw.bytes );
+ *data_length = slot->data.raw.bytes;
+ return( PSA_SUCCESS );
+ }
+ else
+ {
+#if defined(MBEDCRYPTO_PK_WRITE_C)
+ if( PSA_KEY_TYPE_IS_RSA( slot->type ) ||
+ PSA_KEY_TYPE_IS_ECC( slot->type ) )
+ {
+ mbedcrypto_pk_context pk;
+ int ret;
+ if( PSA_KEY_TYPE_IS_RSA( slot->type ) )
+ {
+#if defined(MBEDCRYPTO_RSA_C)
+ mbedcrypto_pk_init( &pk );
+ pk.pk_info = &mbedcrypto_rsa_info;
+ pk.pk_ctx = slot->data.rsa;
+#else
+ return( PSA_ERROR_NOT_SUPPORTED );
+#endif
+ }
+ else
+ {
+#if defined(MBEDCRYPTO_ECP_C)
+ mbedcrypto_pk_init( &pk );
+ pk.pk_info = &mbedcrypto_eckey_info;
+ pk.pk_ctx = slot->data.ecp;
+#else
+ return( PSA_ERROR_NOT_SUPPORTED );
+#endif
+ }
+ if( export_public_key || PSA_KEY_TYPE_IS_PUBLIC_KEY( slot->type ) )
+ ret = mbedcrypto_pk_write_pubkey_der( &pk, data, data_size );
+ else
+ ret = mbedcrypto_pk_write_key_der( &pk, data, data_size );
+ if( ret < 0 )
+ {
+ /* If data_size is 0 then data may be NULL and then the
+ * call to memset would have undefined behavior. */
+ if( data_size != 0 )
+ memset( data, 0, data_size );
+ return( mbedcrypto_to_psa_error( ret ) );
+ }
+ /* The mbedcrypto_pk_xxx functions write to the end of the buffer.
+ * Move the data to the beginning and erase remaining data
+ * at the original location. */
+ if( 2 * (size_t) ret <= data_size )
+ {
+ memcpy( data, data + data_size - ret, ret );
+ memset( data + data_size - ret, 0, ret );
+ }
+ else if( (size_t) ret < data_size )
+ {
+ memmove( data, data + data_size - ret, ret );
+ memset( data + ret, 0, data_size - ret );
+ }
+ *data_length = ret;
+ return( PSA_SUCCESS );
+ }
+ else
+#endif /* defined(MBEDCRYPTO_PK_WRITE_C) */
+ {
+ /* This shouldn't happen in the reference implementation, but
+ it is valid for a special-purpose implementation to omit
+ support for exporting certain key types. */
+ return( PSA_ERROR_NOT_SUPPORTED );
+ }
+ }
+}
+
+psa_status_t psa_export_key( psa_key_slot_t key,
+ uint8_t *data,
+ size_t data_size,
+ size_t *data_length )
+{
+ return( psa_internal_export_key( key, data, data_size,
+ data_length, 0 ) );
+}
+
+psa_status_t psa_export_public_key( psa_key_slot_t key,
+ uint8_t *data,
+ size_t data_size,
+ size_t *data_length )
+{
+ return( psa_internal_export_key( key, data, data_size,
+ data_length, 1 ) );
+}
+
+
+
+/****************************************************************/
+/* Message digests */
+/****************************************************************/
+
+static const mbedcrypto_md_info_t *mbedcrypto_md_info_from_psa( psa_algorithm_t alg )
+{
+ switch( alg )
+ {
+#if defined(MBEDCRYPTO_MD2_C)
+ case PSA_ALG_MD2:
+ return( &mbedcrypto_md2_info );
+#endif
+#if defined(MBEDCRYPTO_MD4_C)
+ case PSA_ALG_MD4:
+ return( &mbedcrypto_md4_info );
+#endif
+#if defined(MBEDCRYPTO_MD5_C)
+ case PSA_ALG_MD5:
+ return( &mbedcrypto_md5_info );
+#endif
+#if defined(MBEDCRYPTO_RIPEMD160_C)
+ case PSA_ALG_RIPEMD160:
+ return( &mbedcrypto_ripemd160_info );
+#endif
+#if defined(MBEDCRYPTO_SHA1_C)
+ case PSA_ALG_SHA_1:
+ return( &mbedcrypto_sha1_info );
+#endif
+#if defined(MBEDCRYPTO_SHA256_C)
+ case PSA_ALG_SHA_224:
+ return( &mbedcrypto_sha224_info );
+ case PSA_ALG_SHA_256:
+ return( &mbedcrypto_sha256_info );
+#endif
+#if defined(MBEDCRYPTO_SHA512_C)
+ case PSA_ALG_SHA_384:
+ return( &mbedcrypto_sha384_info );
+ case PSA_ALG_SHA_512:
+ return( &mbedcrypto_sha512_info );
+#endif
+ default:
+ return( NULL );
+ }
+}
+
+psa_status_t psa_hash_abort( psa_hash_operation_t *operation )
+{
+ switch( operation->alg )
+ {
+ case 0:
+ /* The object has (apparently) been initialized but it is not
+ * in use. It's ok to call abort on such an object, and there's
+ * nothing to do. */
+ break;
+#if defined(MBEDCRYPTO_MD2_C)
+ case PSA_ALG_MD2:
+ mbedcrypto_md2_free( &operation->ctx.md2 );
+ break;
+#endif
+#if defined(MBEDCRYPTO_MD4_C)
+ case PSA_ALG_MD4:
+ mbedcrypto_md4_free( &operation->ctx.md4 );
+ break;
+#endif
+#if defined(MBEDCRYPTO_MD5_C)
+ case PSA_ALG_MD5:
+ mbedcrypto_md5_free( &operation->ctx.md5 );
+ break;
+#endif
+#if defined(MBEDCRYPTO_RIPEMD160_C)
+ case PSA_ALG_RIPEMD160:
+ mbedcrypto_ripemd160_free( &operation->ctx.ripemd160 );
+ break;
+#endif
+#if defined(MBEDCRYPTO_SHA1_C)
+ case PSA_ALG_SHA_1:
+ mbedcrypto_sha1_free( &operation->ctx.sha1 );
+ break;
+#endif
+#if defined(MBEDCRYPTO_SHA256_C)
+ case PSA_ALG_SHA_224:
+ case PSA_ALG_SHA_256:
+ mbedcrypto_sha256_free( &operation->ctx.sha256 );
+ break;
+#endif
+#if defined(MBEDCRYPTO_SHA512_C)
+ case PSA_ALG_SHA_384:
+ case PSA_ALG_SHA_512:
+ mbedcrypto_sha512_free( &operation->ctx.sha512 );
+ break;
+#endif
+ default:
+ return( PSA_ERROR_BAD_STATE );
+ }
+ operation->alg = 0;
+ return( PSA_SUCCESS );
+}
+
+psa_status_t psa_hash_setup( psa_hash_operation_t *operation,
+ psa_algorithm_t alg )
+{
+ int ret;
+ operation->alg = 0;
+ switch( alg )
+ {
+#if defined(MBEDCRYPTO_MD2_C)
+ case PSA_ALG_MD2:
+ mbedcrypto_md2_init( &operation->ctx.md2 );
+ ret = mbedcrypto_md2_starts_ret( &operation->ctx.md2 );
+ break;
+#endif
+#if defined(MBEDCRYPTO_MD4_C)
+ case PSA_ALG_MD4:
+ mbedcrypto_md4_init( &operation->ctx.md4 );
+ ret = mbedcrypto_md4_starts_ret( &operation->ctx.md4 );
+ break;
+#endif
+#if defined(MBEDCRYPTO_MD5_C)
+ case PSA_ALG_MD5:
+ mbedcrypto_md5_init( &operation->ctx.md5 );
+ ret = mbedcrypto_md5_starts_ret( &operation->ctx.md5 );
+ break;
+#endif
+#if defined(MBEDCRYPTO_RIPEMD160_C)
+ case PSA_ALG_RIPEMD160:
+ mbedcrypto_ripemd160_init( &operation->ctx.ripemd160 );
+ ret = mbedcrypto_ripemd160_starts_ret( &operation->ctx.ripemd160 );
+ break;
+#endif
+#if defined(MBEDCRYPTO_SHA1_C)
+ case PSA_ALG_SHA_1:
+ mbedcrypto_sha1_init( &operation->ctx.sha1 );
+ ret = mbedcrypto_sha1_starts_ret( &operation->ctx.sha1 );
+ break;
+#endif
+#if defined(MBEDCRYPTO_SHA256_C)
+ case PSA_ALG_SHA_224:
+ mbedcrypto_sha256_init( &operation->ctx.sha256 );
+ ret = mbedcrypto_sha256_starts_ret( &operation->ctx.sha256, 1 );
+ break;
+ case PSA_ALG_SHA_256:
+ mbedcrypto_sha256_init( &operation->ctx.sha256 );
+ ret = mbedcrypto_sha256_starts_ret( &operation->ctx.sha256, 0 );
+ break;
+#endif
+#if defined(MBEDCRYPTO_SHA512_C)
+ case PSA_ALG_SHA_384:
+ mbedcrypto_sha512_init( &operation->ctx.sha512 );
+ ret = mbedcrypto_sha512_starts_ret( &operation->ctx.sha512, 1 );
+ break;
+ case PSA_ALG_SHA_512:
+ mbedcrypto_sha512_init( &operation->ctx.sha512 );
+ ret = mbedcrypto_sha512_starts_ret( &operation->ctx.sha512, 0 );
+ break;
+#endif
+ default:
+ return( PSA_ALG_IS_HASH( alg ) ?
+ PSA_ERROR_NOT_SUPPORTED :
+ PSA_ERROR_INVALID_ARGUMENT );
+ }
+ if( ret == 0 )
+ operation->alg = alg;
+ else
+ psa_hash_abort( operation );
+ return( mbedcrypto_to_psa_error( ret ) );
+}
+
+psa_status_t psa_hash_update( psa_hash_operation_t *operation,
+ const uint8_t *input,
+ size_t input_length )
+{
+ int ret;
+
+ /* Don't require hash implementations to behave correctly on a
+ * zero-length input, which may have an invalid pointer. */
+ if( input_length == 0 )
+ return( PSA_SUCCESS );
+
+ switch( operation->alg )
+ {
+#if defined(MBEDCRYPTO_MD2_C)
+ case PSA_ALG_MD2:
+ ret = mbedcrypto_md2_update_ret( &operation->ctx.md2,
+ input, input_length );
+ break;
+#endif
+#if defined(MBEDCRYPTO_MD4_C)
+ case PSA_ALG_MD4:
+ ret = mbedcrypto_md4_update_ret( &operation->ctx.md4,
+ input, input_length );
+ break;
+#endif
+#if defined(MBEDCRYPTO_MD5_C)
+ case PSA_ALG_MD5:
+ ret = mbedcrypto_md5_update_ret( &operation->ctx.md5,
+ input, input_length );
+ break;
+#endif
+#if defined(MBEDCRYPTO_RIPEMD160_C)
+ case PSA_ALG_RIPEMD160:
+ ret = mbedcrypto_ripemd160_update_ret( &operation->ctx.ripemd160,
+ input, input_length );
+ break;
+#endif
+#if defined(MBEDCRYPTO_SHA1_C)
+ case PSA_ALG_SHA_1:
+ ret = mbedcrypto_sha1_update_ret( &operation->ctx.sha1,
+ input, input_length );
+ break;
+#endif
+#if defined(MBEDCRYPTO_SHA256_C)
+ case PSA_ALG_SHA_224:
+ case PSA_ALG_SHA_256:
+ ret = mbedcrypto_sha256_update_ret( &operation->ctx.sha256,
+ input, input_length );
+ break;
+#endif
+#if defined(MBEDCRYPTO_SHA512_C)
+ case PSA_ALG_SHA_384:
+ case PSA_ALG_SHA_512:
+ ret = mbedcrypto_sha512_update_ret( &operation->ctx.sha512,
+ input, input_length );
+ break;
+#endif
+ default:
+ ret = MBEDCRYPTO_ERR_MD_BAD_INPUT_DATA;
+ break;
+ }
+
+ if( ret != 0 )
+ psa_hash_abort( operation );
+ return( mbedcrypto_to_psa_error( ret ) );
+}
+
+psa_status_t psa_hash_finish( psa_hash_operation_t *operation,
+ uint8_t *hash,
+ size_t hash_size,
+ size_t *hash_length )
+{
+ int ret;
+ size_t actual_hash_length = PSA_HASH_SIZE( operation->alg );
+
+ /* Fill the output buffer with something that isn't a valid hash
+ * (barring an attack on the hash and deliberately-crafted input),
+ * in case the caller doesn't check the return status properly. */
+ *hash_length = hash_size;
+ /* If hash_size is 0 then hash may be NULL and then the
+ * call to memset would have undefined behavior. */
+ if( hash_size != 0 )
+ memset( hash, '!', hash_size );
+
+ if( hash_size < actual_hash_length )
+ return( PSA_ERROR_BUFFER_TOO_SMALL );
+
+ switch( operation->alg )
+ {
+#if defined(MBEDCRYPTO_MD2_C)
+ case PSA_ALG_MD2:
+ ret = mbedcrypto_md2_finish_ret( &operation->ctx.md2, hash );
+ break;
+#endif
+#if defined(MBEDCRYPTO_MD4_C)
+ case PSA_ALG_MD4:
+ ret = mbedcrypto_md4_finish_ret( &operation->ctx.md4, hash );
+ break;
+#endif
+#if defined(MBEDCRYPTO_MD5_C)
+ case PSA_ALG_MD5:
+ ret = mbedcrypto_md5_finish_ret( &operation->ctx.md5, hash );
+ break;
+#endif
+#if defined(MBEDCRYPTO_RIPEMD160_C)
+ case PSA_ALG_RIPEMD160:
+ ret = mbedcrypto_ripemd160_finish_ret( &operation->ctx.ripemd160, hash );
+ break;
+#endif
+#if defined(MBEDCRYPTO_SHA1_C)
+ case PSA_ALG_SHA_1:
+ ret = mbedcrypto_sha1_finish_ret( &operation->ctx.sha1, hash );
+ break;
+#endif
+#if defined(MBEDCRYPTO_SHA256_C)
+ case PSA_ALG_SHA_224:
+ case PSA_ALG_SHA_256:
+ ret = mbedcrypto_sha256_finish_ret( &operation->ctx.sha256, hash );
+ break;
+#endif
+#if defined(MBEDCRYPTO_SHA512_C)
+ case PSA_ALG_SHA_384:
+ case PSA_ALG_SHA_512:
+ ret = mbedcrypto_sha512_finish_ret( &operation->ctx.sha512, hash );
+ break;
+#endif
+ default:
+ ret = MBEDCRYPTO_ERR_MD_BAD_INPUT_DATA;
+ break;
+ }
+
+ if( ret == 0 )
+ {
+ *hash_length = actual_hash_length;
+ return( psa_hash_abort( operation ) );
+ }
+ else
+ {
+ psa_hash_abort( operation );
+ return( mbedcrypto_to_psa_error( ret ) );
+ }
+}
+
+psa_status_t psa_hash_verify( psa_hash_operation_t *operation,
+ const uint8_t *hash,
+ size_t hash_length )
+{
+ uint8_t actual_hash[MBEDCRYPTO_MD_MAX_SIZE];
+ size_t actual_hash_length;
+ psa_status_t status = psa_hash_finish( operation,
+ actual_hash, sizeof( actual_hash ),
+ &actual_hash_length );
+ if( status != PSA_SUCCESS )
+ return( status );
+ if( actual_hash_length != hash_length )
+ return( PSA_ERROR_INVALID_SIGNATURE );
+ if( safer_memcmp( hash, actual_hash, actual_hash_length ) != 0 )
+ return( PSA_ERROR_INVALID_SIGNATURE );
+ return( PSA_SUCCESS );
+}
+
+
+
+/****************************************************************/
+/* MAC */
+/****************************************************************/
+
+static const mbedcrypto_cipher_info_t *mbedcrypto_cipher_info_from_psa(
+ psa_algorithm_t alg,
+ psa_key_type_t key_type,
+ size_t key_bits,
+ mbedcrypto_cipher_id_t* cipher_id )
+{
+ mbedcrypto_cipher_mode_t mode;
+ mbedcrypto_cipher_id_t cipher_id_tmp;
+
+ if( PSA_ALG_IS_CIPHER( alg ) || PSA_ALG_IS_AEAD( alg ) )
+ {
+ if( PSA_ALG_IS_BLOCK_CIPHER( alg ) )
+ {
+ alg &= ~PSA_ALG_BLOCK_CIPHER_PADDING_MASK;
+ }
+
+ switch( alg )
+ {
+ case PSA_ALG_STREAM_CIPHER_BASE:
+ mode = MBEDCRYPTO_MODE_STREAM;
+ break;
+ case PSA_ALG_CBC_BASE:
+ mode = MBEDCRYPTO_MODE_CBC;
+ break;
+ case PSA_ALG_CFB_BASE:
+ mode = MBEDCRYPTO_MODE_CFB;
+ break;
+ case PSA_ALG_OFB_BASE:
+ mode = MBEDCRYPTO_MODE_OFB;
+ break;
+ case PSA_ALG_CTR:
+ mode = MBEDCRYPTO_MODE_CTR;
+ break;
+ case PSA_ALG_CCM:
+ mode = MBEDCRYPTO_MODE_CCM;
+ break;
+ case PSA_ALG_GCM:
+ mode = MBEDCRYPTO_MODE_GCM;
+ break;
+ default:
+ return( NULL );
+ }
+ }
+ else if( alg == PSA_ALG_CMAC )
+ mode = MBEDCRYPTO_MODE_ECB;
+ else if( alg == PSA_ALG_GMAC )
+ mode = MBEDCRYPTO_MODE_GCM;
+ else
+ return( NULL );
+
+ switch( key_type )
+ {
+ case PSA_KEY_TYPE_AES:
+ cipher_id_tmp = MBEDCRYPTO_CIPHER_ID_AES;
+ break;
+ case PSA_KEY_TYPE_DES:
+ /* key_bits is 64 for Single-DES, 128 for two-key Triple-DES,
+ * and 192 for three-key Triple-DES. */
+ if( key_bits == 64 )
+ cipher_id_tmp = MBEDCRYPTO_CIPHER_ID_DES;
+ else
+ cipher_id_tmp = MBEDCRYPTO_CIPHER_ID_3DES;
+ /* mbedcrypto doesn't recognize two-key Triple-DES as an algorithm,
+ * but two-key Triple-DES is functionally three-key Triple-DES
+ * with K1=K3, so that's how we present it to mbedcrypto. */
+ if( key_bits == 128 )
+ key_bits = 192;
+ break;
+ case PSA_KEY_TYPE_CAMELLIA:
+ cipher_id_tmp = MBEDCRYPTO_CIPHER_ID_CAMELLIA;
+ break;
+ case PSA_KEY_TYPE_ARC4:
+ cipher_id_tmp = MBEDCRYPTO_CIPHER_ID_ARC4;
+ break;
+ default:
+ return( NULL );
+ }
+ if( cipher_id != NULL )
+ *cipher_id = cipher_id_tmp;
+
+ return( mbedcrypto_cipher_info_from_values( cipher_id_tmp,
+ (int) key_bits, mode ) );
+}
+
+static size_t psa_get_hash_block_size( psa_algorithm_t alg )
+{
+ switch( alg )
+ {
+ case PSA_ALG_MD2:
+ return( 16 );
+ case PSA_ALG_MD4:
+ return( 64 );
+ case PSA_ALG_MD5:
+ return( 64 );
+ case PSA_ALG_RIPEMD160:
+ return( 64 );
+ case PSA_ALG_SHA_1:
+ return( 64 );
+ case PSA_ALG_SHA_224:
+ return( 64 );
+ case PSA_ALG_SHA_256:
+ return( 64 );
+ case PSA_ALG_SHA_384:
+ return( 128 );
+ case PSA_ALG_SHA_512:
+ return( 128 );
+ default:
+ return( 0 );
+ }
+}
+
+/* Initialize the MAC operation structure. Once this function has been
+ * called, psa_mac_abort can run and will do the right thing. */
+static psa_status_t psa_mac_init( psa_mac_operation_t *operation,
+ psa_algorithm_t alg )
+{
+ psa_status_t status = PSA_ERROR_NOT_SUPPORTED;
+
+ operation->alg = alg;
+ operation->key_set = 0;
+ operation->iv_set = 0;
+ operation->iv_required = 0;
+ operation->has_input = 0;
+ operation->is_sign = 0;
+
+#if defined(MBEDCRYPTO_CMAC_C)
+ if( alg == PSA_ALG_CMAC )
+ {
+ operation->iv_required = 0;
+ mbedcrypto_cipher_init( &operation->ctx.cmac );
+ status = PSA_SUCCESS;
+ }
+ else
+#endif /* MBEDCRYPTO_CMAC_C */
+#if defined(MBEDCRYPTO_MD_C)
+ if( PSA_ALG_IS_HMAC( operation->alg ) )
+ {
+ /* We'll set up the hash operation later in psa_hmac_setup_internal. */
+ operation->ctx.hmac.hash_ctx.alg = 0;
+ status = PSA_SUCCESS;
+ }
+ else
+#endif /* MBEDCRYPTO_MD_C */
+ {
+ if( ! PSA_ALG_IS_MAC( alg ) )
+ status = PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ if( status != PSA_SUCCESS )
+ memset( operation, 0, sizeof( *operation ) );
+ return( status );
+}
+
+#if defined(MBEDCRYPTO_MD_C)
+static psa_status_t psa_hmac_abort_internal( psa_hmac_internal_data *hmac )
+{
+ mbedcrypto_zeroize( hmac->opad, sizeof( hmac->opad ) );
+ return( psa_hash_abort( &hmac->hash_ctx ) );
+}
+#endif /* MBEDCRYPTO_MD_C */
+
+psa_status_t psa_mac_abort( psa_mac_operation_t *operation )
+{
+ if( operation->alg == 0 )
+ {
+ /* The object has (apparently) been initialized but it is not
+ * in use. It's ok to call abort on such an object, and there's
+ * nothing to do. */
+ return( PSA_SUCCESS );
+ }
+ else
+#if defined(MBEDCRYPTO_CMAC_C)
+ if( operation->alg == PSA_ALG_CMAC )
+ {
+ mbedcrypto_cipher_free( &operation->ctx.cmac );
+ }
+ else
+#endif /* MBEDCRYPTO_CMAC_C */
+#if defined(MBEDCRYPTO_MD_C)
+ if( PSA_ALG_IS_HMAC( operation->alg ) )
+ {
+ psa_hmac_abort_internal( &operation->ctx.hmac );
+ }
+ else
+#endif /* MBEDCRYPTO_MD_C */
+ {
+ /* Sanity check (shouldn't happen: operation->alg should
+ * always have been initialized to a valid value). */
+ goto bad_state;
+ }
+
+ operation->alg = 0;
+ operation->key_set = 0;
+ operation->iv_set = 0;
+ operation->iv_required = 0;
+ operation->has_input = 0;
+ operation->is_sign = 0;
+
+ return( PSA_SUCCESS );
+
+bad_state:
+ /* If abort is called on an uninitialized object, we can't trust
+ * anything. Wipe the object in case it contains confidential data.
+ * This may result in a memory leak if a pointer gets overwritten,
+ * but it's too late to do anything about this. */
+ memset( operation, 0, sizeof( *operation ) );
+ return( PSA_ERROR_BAD_STATE );
+}
+
+#if defined(MBEDCRYPTO_CMAC_C)
+static int psa_cmac_setup( psa_mac_operation_t *operation,
+ size_t key_bits,
+ key_slot_t *slot,
+ const mbedcrypto_cipher_info_t *cipher_info )
+{
+ int ret;
+
+ operation->mac_size = cipher_info->block_size;
+
+ ret = mbedcrypto_cipher_setup( &operation->ctx.cmac, cipher_info );
+ if( ret != 0 )
+ return( ret );
+
+ ret = mbedcrypto_cipher_cmac_starts( &operation->ctx.cmac,
+ slot->data.raw.data,
+ key_bits );
+ return( ret );
+}
+#endif /* MBEDCRYPTO_CMAC_C */
+
+#if defined(MBEDCRYPTO_MD_C)
+static psa_status_t psa_hmac_setup_internal( psa_hmac_internal_data *hmac,
+ const uint8_t *key,
+ size_t key_length,
+ psa_algorithm_t hash_alg )
+{
+ unsigned char ipad[PSA_HMAC_MAX_HASH_BLOCK_SIZE];
+ size_t i;
+ size_t hash_size = PSA_HASH_SIZE( hash_alg );
+ size_t block_size = psa_get_hash_block_size( hash_alg );
+ psa_status_t status;
+
+ /* Sanity checks on block_size, to guarantee that there won't be a buffer
+ * overflow below. This should never trigger if the hash algorithm
+ * is implemented correctly. */
+ /* The size checks against the ipad and opad buffers cannot be written
+ * `block_size > sizeof( ipad ) || block_size > sizeof( hmac->opad )`
+ * because that triggers -Wlogical-op on GCC 7.3. */
+ if( block_size > sizeof( ipad ) )
+ return( PSA_ERROR_NOT_SUPPORTED );
+ if( block_size > sizeof( hmac->opad ) )
+ return( PSA_ERROR_NOT_SUPPORTED );
+ if( block_size < hash_size )
+ return( PSA_ERROR_NOT_SUPPORTED );
+
+ if( key_length > block_size )
+ {
+ status = psa_hash_setup( &hmac->hash_ctx, hash_alg );
+ if( status != PSA_SUCCESS )
+ goto cleanup;
+ status = psa_hash_update( &hmac->hash_ctx, key, key_length );
+ if( status != PSA_SUCCESS )
+ goto cleanup;
+ status = psa_hash_finish( &hmac->hash_ctx,
+ ipad, sizeof( ipad ), &key_length );
+ if( status != PSA_SUCCESS )
+ goto cleanup;
+ }
+ /* A 0-length key is not commonly used in HMAC when used as a MAC,
+ * but it is permitted. It is common when HMAC is used in HKDF, for
+ * example. Don't call `memcpy` in the 0-length because `key` could be
+ * an invalid pointer which would make the behavior undefined. */
+ else if( key_length != 0 )
+ memcpy( ipad, key, key_length );
+
+ /* ipad contains the key followed by garbage. Xor and fill with 0x36
+ * to create the ipad value. */
+ for( i = 0; i < key_length; i++ )
+ ipad[i] ^= 0x36;
+ memset( ipad + key_length, 0x36, block_size - key_length );
+
+ /* Copy the key material from ipad to opad, flipping the requisite bits,
+ * and filling the rest of opad with the requisite constant. */
+ for( i = 0; i < key_length; i++ )
+ hmac->opad[i] = ipad[i] ^ 0x36 ^ 0x5C;
+ memset( hmac->opad + key_length, 0x5C, block_size - key_length );
+
+ status = psa_hash_setup( &hmac->hash_ctx, hash_alg );
+ if( status != PSA_SUCCESS )
+ goto cleanup;
+
+ status = psa_hash_update( &hmac->hash_ctx, ipad, block_size );
+
+cleanup:
+ mbedcrypto_zeroize( ipad, key_length );
+
+ return( status );
+}
+#endif /* MBEDCRYPTO_MD_C */
+
+static psa_status_t psa_mac_setup( psa_mac_operation_t *operation,
+ psa_key_slot_t key,
+ psa_algorithm_t alg,
+ int is_sign )
+{
+ psa_status_t status;
+ key_slot_t *slot;
+ size_t key_bits;
+ psa_key_usage_t usage =
+ is_sign ? PSA_KEY_USAGE_SIGN : PSA_KEY_USAGE_VERIFY;
+
+ status = psa_mac_init( operation, alg );
+ if( status != PSA_SUCCESS )
+ return( status );
+ if( is_sign )
+ operation->is_sign = 1;
+
+ status = psa_get_key_from_slot( key, &slot, usage, alg );
+ if( status != PSA_SUCCESS )
+ goto exit;
+ key_bits = psa_get_key_bits( slot );
+
+#if defined(MBEDCRYPTO_CMAC_C)
+ if( alg == PSA_ALG_CMAC )
+ {
+ const mbedcrypto_cipher_info_t *cipher_info =
+ mbedcrypto_cipher_info_from_psa( alg, slot->type, key_bits, NULL );
+ int ret;
+ if( cipher_info == NULL )
+ {
+ status = PSA_ERROR_NOT_SUPPORTED;
+ goto exit;
+ }
+ operation->mac_size = cipher_info->block_size;
+ ret = psa_cmac_setup( operation, key_bits, slot, cipher_info );
+ status = mbedcrypto_to_psa_error( ret );
+ }
+ else
+#endif /* MBEDCRYPTO_CMAC_C */
+#if defined(MBEDCRYPTO_MD_C)
+ if( PSA_ALG_IS_HMAC( alg ) )
+ {
+ psa_algorithm_t hash_alg = PSA_ALG_HMAC_HASH( alg );
+ if( hash_alg == 0 )
+ {
+ status = PSA_ERROR_NOT_SUPPORTED;
+ goto exit;
+ }
+
+ operation->mac_size = PSA_HASH_SIZE( hash_alg );
+ /* Sanity check. This shouldn't fail on a valid configuration. */
+ if( operation->mac_size == 0 ||
+ operation->mac_size > sizeof( operation->ctx.hmac.opad ) )
+ {
+ status = PSA_ERROR_NOT_SUPPORTED;
+ goto exit;
+ }
+
+ if( slot->type != PSA_KEY_TYPE_HMAC )
+ {
+ status = PSA_ERROR_INVALID_ARGUMENT;
+ goto exit;
+ }
+
+ status = psa_hmac_setup_internal( &operation->ctx.hmac,
+ slot->data.raw.data,
+ slot->data.raw.bytes,
+ hash_alg );
+ }
+ else
+#endif /* MBEDCRYPTO_MD_C */
+ {
+ status = PSA_ERROR_NOT_SUPPORTED;
+ }
+
+exit:
+ if( status != PSA_SUCCESS )
+ {
+ psa_mac_abort( operation );
+ }
+ else
+ {
+ operation->key_set = 1;
+ }
+ return( status );
+}
+
+psa_status_t psa_mac_sign_setup( psa_mac_operation_t *operation,
+ psa_key_slot_t key,
+ psa_algorithm_t alg )
+{
+ return( psa_mac_setup( operation, key, alg, 1 ) );
+}
+
+psa_status_t psa_mac_verify_setup( psa_mac_operation_t *operation,
+ psa_key_slot_t key,
+ psa_algorithm_t alg )
+{
+ return( psa_mac_setup( operation, key, alg, 0 ) );
+}
+
+psa_status_t psa_mac_update( psa_mac_operation_t *operation,
+ const uint8_t *input,
+ size_t input_length )
+{
+ psa_status_t status = PSA_ERROR_BAD_STATE;
+ if( ! operation->key_set )
+ goto cleanup;
+ if( operation->iv_required && ! operation->iv_set )
+ goto cleanup;
+ operation->has_input = 1;
+
+#if defined(MBEDCRYPTO_CMAC_C)
+ if( operation->alg == PSA_ALG_CMAC )
+ {
+ int ret = mbedcrypto_cipher_cmac_update( &operation->ctx.cmac,
+ input, input_length );
+ status = mbedcrypto_to_psa_error( ret );
+ }
+ else
+#endif /* MBEDCRYPTO_CMAC_C */
+#if defined(MBEDCRYPTO_MD_C)
+ if( PSA_ALG_IS_HMAC( operation->alg ) )
+ {
+ status = psa_hash_update( &operation->ctx.hmac.hash_ctx, input,
+ input_length );
+ }
+ else
+#endif /* MBEDCRYPTO_MD_C */
+ {
+ /* This shouldn't happen if `operation` was initialized by
+ * a setup function. */
+ status = PSA_ERROR_BAD_STATE;
+ }
+
+cleanup:
+ if( status != PSA_SUCCESS )
+ psa_mac_abort( operation );
+ return( status );
+}
+
+#if defined(MBEDCRYPTO_MD_C)
+static psa_status_t psa_hmac_finish_internal( psa_hmac_internal_data *hmac,
+ uint8_t *mac,
+ size_t mac_size )
+{
+ unsigned char tmp[MBEDCRYPTO_MD_MAX_SIZE];
+ psa_algorithm_t hash_alg = hmac->hash_ctx.alg;
+ size_t hash_size = 0;
+ size_t block_size = psa_get_hash_block_size( hash_alg );
+ psa_status_t status;
+
+ status = psa_hash_finish( &hmac->hash_ctx, tmp, sizeof( tmp ), &hash_size );
+ if( status != PSA_SUCCESS )
+ return( status );
+ /* From here on, tmp needs to be wiped. */
+
+ status = psa_hash_setup( &hmac->hash_ctx, hash_alg );
+ if( status != PSA_SUCCESS )
+ goto exit;
+
+ status = psa_hash_update( &hmac->hash_ctx, hmac->opad, block_size );
+ if( status != PSA_SUCCESS )
+ goto exit;
+
+ status = psa_hash_update( &hmac->hash_ctx, tmp, hash_size );
+ if( status != PSA_SUCCESS )
+ goto exit;
+
+ status = psa_hash_finish( &hmac->hash_ctx, mac, mac_size, &hash_size );
+
+exit:
+ mbedcrypto_zeroize( tmp, hash_size );
+ return( status );
+}
+#endif /* MBEDCRYPTO_MD_C */
+
+static psa_status_t psa_mac_finish_internal( psa_mac_operation_t *operation,
+ uint8_t *mac,
+ size_t mac_size )
+{
+ if( ! operation->key_set )
+ return( PSA_ERROR_BAD_STATE );
+ if( operation->iv_required && ! operation->iv_set )
+ return( PSA_ERROR_BAD_STATE );
+
+ if( mac_size < operation->mac_size )
+ return( PSA_ERROR_BUFFER_TOO_SMALL );
+
+#if defined(MBEDCRYPTO_CMAC_C)
+ if( operation->alg == PSA_ALG_CMAC )
+ {
+ int ret = mbedcrypto_cipher_cmac_finish( &operation->ctx.cmac, mac );
+ return( mbedcrypto_to_psa_error( ret ) );
+ }
+ else
+#endif /* MBEDCRYPTO_CMAC_C */
+#if defined(MBEDCRYPTO_MD_C)
+ if( PSA_ALG_IS_HMAC( operation->alg ) )
+ {
+ return( psa_hmac_finish_internal( &operation->ctx.hmac,
+ mac, mac_size ) );
+ }
+ else
+#endif /* MBEDCRYPTO_MD_C */
+ {
+ /* This shouldn't happen if `operation` was initialized by
+ * a setup function. */
+ return( PSA_ERROR_BAD_STATE );
+ }
+}
+
+psa_status_t psa_mac_sign_finish( psa_mac_operation_t *operation,
+ uint8_t *mac,
+ size_t mac_size,
+ size_t *mac_length )
+{
+ psa_status_t status;
+
+ /* Fill the output buffer with something that isn't a valid mac
+ * (barring an attack on the mac and deliberately-crafted input),
+ * in case the caller doesn't check the return status properly. */
+ *mac_length = mac_size;
+ /* If mac_size is 0 then mac may be NULL and then the
+ * call to memset would have undefined behavior. */
+ if( mac_size != 0 )
+ memset( mac, '!', mac_size );
+
+ if( ! operation->is_sign )
+ {
+ status = PSA_ERROR_BAD_STATE;
+ goto cleanup;
+ }
+
+ status = psa_mac_finish_internal( operation, mac, mac_size );
+
+cleanup:
+ if( status == PSA_SUCCESS )
+ {
+ status = psa_mac_abort( operation );
+ if( status == PSA_SUCCESS )
+ *mac_length = operation->mac_size;
+ else
+ memset( mac, '!', mac_size );
+ }
+ else
+ psa_mac_abort( operation );
+ return( status );
+}
+
+psa_status_t psa_mac_verify_finish( psa_mac_operation_t *operation,
+ const uint8_t *mac,
+ size_t mac_length )
+{
+ uint8_t actual_mac[PSA_MAC_MAX_SIZE];
+ psa_status_t status;
+
+ if( operation->is_sign )
+ {
+ status = PSA_ERROR_BAD_STATE;
+ goto cleanup;
+ }
+ if( operation->mac_size != mac_length )
+ {
+ status = PSA_ERROR_INVALID_SIGNATURE;
+ goto cleanup;
+ }
+
+ status = psa_mac_finish_internal( operation,
+ actual_mac, sizeof( actual_mac ) );
+
+ if( safer_memcmp( mac, actual_mac, mac_length ) != 0 )
+ status = PSA_ERROR_INVALID_SIGNATURE;
+
+cleanup:
+ if( status == PSA_SUCCESS )
+ status = psa_mac_abort( operation );
+ else
+ psa_mac_abort( operation );
+
+ return( status );
+}
+
+
+
+/****************************************************************/
+/* Asymmetric cryptography */
+/****************************************************************/
+
+#if defined(MBEDCRYPTO_RSA_C)
+/* Decode the hash algorithm from alg and store the mbedcrypto encoding in
+ * md_alg. Verify that the hash length is acceptable. */
+static psa_status_t psa_rsa_decode_md_type( psa_algorithm_t alg,
+ size_t hash_length,
+ mbedcrypto_md_type_t *md_alg )
+{
+ psa_algorithm_t hash_alg = PSA_ALG_SIGN_GET_HASH( alg );
+ const mbedcrypto_md_info_t *md_info = mbedcrypto_md_info_from_psa( hash_alg );
+ *md_alg = mbedcrypto_md_get_type( md_info );
+
+ /* The Mbed Crypto RSA module uses an unsigned int for hash length
+ * parameters. Validate that it fits so that we don't risk an
+ * overflow later. */
+#if SIZE_MAX > UINT_MAX
+ if( hash_length > UINT_MAX )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+#endif
+
+#if defined(MBEDCRYPTO_PKCS1_V15)
+ /* For PKCS#1 v1.5 signature, if using a hash, the hash length
+ * must be correct. */
+ if( PSA_ALG_IS_RSA_PKCS1V15_SIGN( alg ) &&
+ alg != PSA_ALG_RSA_PKCS1V15_SIGN_RAW )
+ {
+ if( md_info == NULL )
+ return( PSA_ERROR_NOT_SUPPORTED );
+ if( mbedcrypto_md_get_size( md_info ) != hash_length )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ }
+#endif /* MBEDCRYPTO_PKCS1_V15 */
+
+#if defined(MBEDCRYPTO_PKCS1_V21)
+ /* PSS requires a hash internally. */
+ if( PSA_ALG_IS_RSA_PSS( alg ) )
+ {
+ if( md_info == NULL )
+ return( PSA_ERROR_NOT_SUPPORTED );
+ }
+#endif /* MBEDCRYPTO_PKCS1_V21 */
+
+ return( PSA_SUCCESS );
+}
+
+static psa_status_t psa_rsa_sign( mbedcrypto_rsa_context *rsa,
+ psa_algorithm_t alg,
+ const uint8_t *hash,
+ size_t hash_length,
+ uint8_t *signature,
+ size_t signature_size,
+ size_t *signature_length )
+{
+ psa_status_t status;
+ int ret;
+ mbedcrypto_md_type_t md_alg;
+
+ status = psa_rsa_decode_md_type( alg, hash_length, &md_alg );
+ if( status != PSA_SUCCESS )
+ return( status );
+
+ if( signature_size < mbedcrypto_rsa_get_len( rsa ) )
+ return( PSA_ERROR_BUFFER_TOO_SMALL );
+
+#if defined(MBEDCRYPTO_PKCS1_V15)
+ if( PSA_ALG_IS_RSA_PKCS1V15_SIGN( alg ) )
+ {
+ mbedcrypto_rsa_set_padding( rsa, MBEDCRYPTO_RSA_PKCS_V15,
+ MBEDCRYPTO_MD_NONE );
+ ret = mbedcrypto_rsa_pkcs1_sign( rsa,
+ mbedcrypto_ctr_drbg_random,
+ &global_data.ctr_drbg,
+ MBEDCRYPTO_RSA_PRIVATE,
+ md_alg,
+ (unsigned int) hash_length,
+ hash,
+ signature );
+ }
+ else
+#endif /* MBEDCRYPTO_PKCS1_V15 */
+#if defined(MBEDCRYPTO_PKCS1_V21)
+ if( PSA_ALG_IS_RSA_PSS( alg ) )
+ {
+ mbedcrypto_rsa_set_padding( rsa, MBEDCRYPTO_RSA_PKCS_V21, md_alg );
+ ret = mbedcrypto_rsa_rsassa_pss_sign( rsa,
+ mbedcrypto_ctr_drbg_random,
+ &global_data.ctr_drbg,
+ MBEDCRYPTO_RSA_PRIVATE,
+ MBEDCRYPTO_MD_NONE,
+ (unsigned int) hash_length,
+ hash,
+ signature );
+ }
+ else
+#endif /* MBEDCRYPTO_PKCS1_V21 */
+ {
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ }
+
+ if( ret == 0 )
+ *signature_length = mbedcrypto_rsa_get_len( rsa );
+ return( mbedcrypto_to_psa_error( ret ) );
+}
+
+static psa_status_t psa_rsa_verify( mbedcrypto_rsa_context *rsa,
+ psa_algorithm_t alg,
+ const uint8_t *hash,
+ size_t hash_length,
+ const uint8_t *signature,
+ size_t signature_length )
+{
+ psa_status_t status;
+ int ret;
+ mbedcrypto_md_type_t md_alg;
+
+ status = psa_rsa_decode_md_type( alg, hash_length, &md_alg );
+ if( status != PSA_SUCCESS )
+ return( status );
+
+ if( signature_length < mbedcrypto_rsa_get_len( rsa ) )
+ return( PSA_ERROR_BUFFER_TOO_SMALL );
+
+#if defined(MBEDCRYPTO_PKCS1_V15)
+ if( PSA_ALG_IS_RSA_PKCS1V15_SIGN( alg ) )
+ {
+ mbedcrypto_rsa_set_padding( rsa, MBEDCRYPTO_RSA_PKCS_V15,
+ MBEDCRYPTO_MD_NONE );
+ ret = mbedcrypto_rsa_pkcs1_verify( rsa,
+ mbedcrypto_ctr_drbg_random,
+ &global_data.ctr_drbg,
+ MBEDCRYPTO_RSA_PUBLIC,
+ md_alg,
+ (unsigned int) hash_length,
+ hash,
+ signature );
+ }
+ else
+#endif /* MBEDCRYPTO_PKCS1_V15 */
+#if defined(MBEDCRYPTO_PKCS1_V21)
+ if( PSA_ALG_IS_RSA_PSS( alg ) )
+ {
+ mbedcrypto_rsa_set_padding( rsa, MBEDCRYPTO_RSA_PKCS_V21, md_alg );
+ ret = mbedcrypto_rsa_rsassa_pss_verify( rsa,
+ mbedcrypto_ctr_drbg_random,
+ &global_data.ctr_drbg,
+ MBEDCRYPTO_RSA_PUBLIC,
+ MBEDCRYPTO_MD_NONE,
+ (unsigned int) hash_length,
+ hash,
+ signature );
+ }
+ else
+#endif /* MBEDCRYPTO_PKCS1_V21 */
+ {
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ }
+ return( mbedcrypto_to_psa_error( ret ) );
+}
+#endif /* MBEDCRYPTO_RSA_C */
+
+#if defined(MBEDCRYPTO_ECDSA_C)
+/* `ecp` cannot be const because `ecp->grp` needs to be non-const
+ * for mbedcrypto_ecdsa_sign() and mbedcrypto_ecdsa_sign_det()
+ * (even though these functions don't modify it). */
+static psa_status_t psa_ecdsa_sign( mbedcrypto_ecp_keypair *ecp,
+ psa_algorithm_t alg,
+ const uint8_t *hash,
+ size_t hash_length,
+ uint8_t *signature,
+ size_t signature_size,
+ size_t *signature_length )
+{
+ int ret;
+ mbedcrypto_mpi r, s;
+ size_t curve_bytes = PSA_BITS_TO_BYTES( ecp->grp.pbits );
+ mbedcrypto_mpi_init( &r );
+ mbedcrypto_mpi_init( &s );
+
+ if( signature_size < 2 * curve_bytes )
+ {
+ ret = MBEDCRYPTO_ERR_ECP_BUFFER_TOO_SMALL;
+ goto cleanup;
+ }
+
+ if( PSA_ALG_DSA_IS_DETERMINISTIC( alg ) )
+ {
+ psa_algorithm_t hash_alg = PSA_ALG_SIGN_GET_HASH( alg );
+ const mbedcrypto_md_info_t *md_info = mbedcrypto_md_info_from_psa( hash_alg );
+ mbedcrypto_md_type_t md_alg = mbedcrypto_md_get_type( md_info );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_ecdsa_sign_det( &ecp->grp, &r, &s, &ecp->d,
+ hash, hash_length,
+ md_alg ) );
+ }
+ else
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_ecdsa_sign( &ecp->grp, &r, &s, &ecp->d,
+ hash, hash_length,
+ mbedcrypto_ctr_drbg_random,
+ &global_data.ctr_drbg ) );
+ }
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_write_binary( &r,
+ signature,
+ curve_bytes ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_write_binary( &s,
+ signature + curve_bytes,
+ curve_bytes ) );
+
+cleanup:
+ mbedcrypto_mpi_free( &r );
+ mbedcrypto_mpi_free( &s );
+ if( ret == 0 )
+ *signature_length = 2 * curve_bytes;
+ return( mbedcrypto_to_psa_error( ret ) );
+}
+
+static psa_status_t psa_ecdsa_verify( mbedcrypto_ecp_keypair *ecp,
+ const uint8_t *hash,
+ size_t hash_length,
+ const uint8_t *signature,
+ size_t signature_length )
+{
+ int ret;
+ mbedcrypto_mpi r, s;
+ size_t curve_bytes = PSA_BITS_TO_BYTES( ecp->grp.pbits );
+ mbedcrypto_mpi_init( &r );
+ mbedcrypto_mpi_init( &s );
+
+ if( signature_length != 2 * curve_bytes )
+ return( PSA_ERROR_INVALID_SIGNATURE );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_binary( &r,
+ signature,
+ curve_bytes ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_binary( &s,
+ signature + curve_bytes,
+ curve_bytes ) );
+
+ ret = mbedcrypto_ecdsa_verify( &ecp->grp, hash, hash_length,
+ &ecp->Q, &r, &s );
+
+cleanup:
+ mbedcrypto_mpi_free( &r );
+ mbedcrypto_mpi_free( &s );
+ return( mbedcrypto_to_psa_error( ret ) );
+}
+#endif /* MBEDCRYPTO_ECDSA_C */
+
+psa_status_t psa_asymmetric_sign( psa_key_slot_t key,
+ psa_algorithm_t alg,
+ const uint8_t *hash,
+ size_t hash_length,
+ uint8_t *signature,
+ size_t signature_size,
+ size_t *signature_length )
+{
+ key_slot_t *slot;
+ psa_status_t status;
+
+ *signature_length = signature_size;
+
+ status = psa_get_key_from_slot( key, &slot, PSA_KEY_USAGE_SIGN, alg );
+ if( status != PSA_SUCCESS )
+ goto exit;
+ if( ! PSA_KEY_TYPE_IS_KEYPAIR( slot->type ) )
+ {
+ status = PSA_ERROR_INVALID_ARGUMENT;
+ goto exit;
+ }
+
+#if defined(MBEDCRYPTO_RSA_C)
+ if( slot->type == PSA_KEY_TYPE_RSA_KEYPAIR )
+ {
+ status = psa_rsa_sign( slot->data.rsa,
+ alg,
+ hash, hash_length,
+ signature, signature_size,
+ signature_length );
+ }
+ else
+#endif /* defined(MBEDCRYPTO_RSA_C) */
+#if defined(MBEDCRYPTO_ECP_C)
+ if( PSA_KEY_TYPE_IS_ECC( slot->type ) )
+ {
+#if defined(MBEDCRYPTO_ECDSA_C)
+ if( PSA_ALG_IS_ECDSA( alg ) )
+ status = psa_ecdsa_sign( slot->data.ecp,
+ alg,
+ hash, hash_length,
+ signature, signature_size,
+ signature_length );
+ else
+#endif /* defined(MBEDCRYPTO_ECDSA_C) */
+ {
+ status = PSA_ERROR_INVALID_ARGUMENT;
+ }
+ }
+ else
+#endif /* defined(MBEDCRYPTO_ECP_C) */
+ {
+ status = PSA_ERROR_NOT_SUPPORTED;
+ }
+
+exit:
+ /* Fill the unused part of the output buffer (the whole buffer on error,
+ * the trailing part on success) with something that isn't a valid mac
+ * (barring an attack on the mac and deliberately-crafted input),
+ * in case the caller doesn't check the return status properly. */
+ if( status == PSA_SUCCESS )
+ memset( signature + *signature_length, '!',
+ signature_size - *signature_length );
+ else if( signature_size != 0 )
+ memset( signature, '!', signature_size );
+ /* If signature_size is 0 then we have nothing to do. We must not call
+ * memset because signature may be NULL in this case. */
+ return( status );
+}
+
+psa_status_t psa_asymmetric_verify( psa_key_slot_t key,
+ psa_algorithm_t alg,
+ const uint8_t *hash,
+ size_t hash_length,
+ const uint8_t *signature,
+ size_t signature_length )
+{
+ key_slot_t *slot;
+ psa_status_t status;
+
+ status = psa_get_key_from_slot( key, &slot, PSA_KEY_USAGE_VERIFY, alg );
+ if( status != PSA_SUCCESS )
+ return( status );
+
+#if defined(MBEDCRYPTO_RSA_C)
+ if( PSA_KEY_TYPE_IS_RSA( slot->type ) )
+ {
+ return( psa_rsa_verify( slot->data.rsa,
+ alg,
+ hash, hash_length,
+ signature, signature_length ) );
+ }
+ else
+#endif /* defined(MBEDCRYPTO_RSA_C) */
+#if defined(MBEDCRYPTO_ECP_C)
+ if( PSA_KEY_TYPE_IS_ECC( slot->type ) )
+ {
+#if defined(MBEDCRYPTO_ECDSA_C)
+ if( PSA_ALG_IS_ECDSA( alg ) )
+ return( psa_ecdsa_verify( slot->data.ecp,
+ hash, hash_length,
+ signature, signature_length ) );
+ else
+#endif /* defined(MBEDCRYPTO_ECDSA_C) */
+ {
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ }
+ }
+ else
+#endif /* defined(MBEDCRYPTO_ECP_C) */
+ {
+ return( PSA_ERROR_NOT_SUPPORTED );
+ }
+}
+
+#if defined(MBEDCRYPTO_RSA_C) && defined(MBEDCRYPTO_PKCS1_V21)
+static void psa_rsa_oaep_set_padding_mode( psa_algorithm_t alg,
+ mbedcrypto_rsa_context *rsa )
+{
+ psa_algorithm_t hash_alg = PSA_ALG_RSA_OAEP_GET_HASH( alg );
+ const mbedcrypto_md_info_t *md_info = mbedcrypto_md_info_from_psa( hash_alg );
+ mbedcrypto_md_type_t md_alg = mbedcrypto_md_get_type( md_info );
+ mbedcrypto_rsa_set_padding( rsa, MBEDCRYPTO_RSA_PKCS_V21, md_alg );
+}
+#endif /* defined(MBEDCRYPTO_RSA_C) && defined(MBEDCRYPTO_PKCS1_V21) */
+
+psa_status_t psa_asymmetric_encrypt( psa_key_slot_t key,
+ psa_algorithm_t alg,
+ const uint8_t *input,
+ size_t input_length,
+ const uint8_t *salt,
+ size_t salt_length,
+ uint8_t *output,
+ size_t output_size,
+ size_t *output_length )
+{
+ key_slot_t *slot;
+ psa_status_t status;
+
+ (void) input;
+ (void) input_length;
+ (void) salt;
+ (void) output;
+ (void) output_size;
+
+ *output_length = 0;
+
+ if( ! PSA_ALG_IS_RSA_OAEP( alg ) && salt_length != 0 )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+
+ status = psa_get_key_from_slot( key, &slot, PSA_KEY_USAGE_ENCRYPT, alg );
+ if( status != PSA_SUCCESS )
+ return( status );
+ if( ! ( PSA_KEY_TYPE_IS_PUBLIC_KEY( slot->type ) ||
+ PSA_KEY_TYPE_IS_KEYPAIR( slot->type ) ) )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+
+#if defined(MBEDCRYPTO_RSA_C)
+ if( PSA_KEY_TYPE_IS_RSA( slot->type ) )
+ {
+ mbedcrypto_rsa_context *rsa = slot->data.rsa;
+ int ret;
+ if( output_size < mbedcrypto_rsa_get_len( rsa ) )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+#if defined(MBEDCRYPTO_PKCS1_V15)
+ if( alg == PSA_ALG_RSA_PKCS1V15_CRYPT )
+ {
+ ret = mbedcrypto_rsa_pkcs1_encrypt( rsa,
+ mbedcrypto_ctr_drbg_random,
+ &global_data.ctr_drbg,
+ MBEDCRYPTO_RSA_PUBLIC,
+ input_length,
+ input,
+ output );
+ }
+ else
+#endif /* MBEDCRYPTO_PKCS1_V15 */
+#if defined(MBEDCRYPTO_PKCS1_V21)
+ if( PSA_ALG_IS_RSA_OAEP( alg ) )
+ {
+ psa_rsa_oaep_set_padding_mode( alg, rsa );
+ ret = mbedcrypto_rsa_rsaes_oaep_encrypt( rsa,
+ mbedcrypto_ctr_drbg_random,
+ &global_data.ctr_drbg,
+ MBEDCRYPTO_RSA_PUBLIC,
+ salt, salt_length,
+ input_length,
+ input,
+ output );
+ }
+ else
+#endif /* MBEDCRYPTO_PKCS1_V21 */
+ {
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ }
+ if( ret == 0 )
+ *output_length = mbedcrypto_rsa_get_len( rsa );
+ return( mbedcrypto_to_psa_error( ret ) );
+ }
+ else
+#endif /* defined(MBEDCRYPTO_RSA_C) */
+ {
+ return( PSA_ERROR_NOT_SUPPORTED );
+ }
+}
+
+psa_status_t psa_asymmetric_decrypt( psa_key_slot_t key,
+ psa_algorithm_t alg,
+ const uint8_t *input,
+ size_t input_length,
+ const uint8_t *salt,
+ size_t salt_length,
+ uint8_t *output,
+ size_t output_size,
+ size_t *output_length )
+{
+ key_slot_t *slot;
+ psa_status_t status;
+
+ (void) input;
+ (void) input_length;
+ (void) salt;
+ (void) output;
+ (void) output_size;
+
+ *output_length = 0;
+
+ if( ! PSA_ALG_IS_RSA_OAEP( alg ) && salt_length != 0 )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+
+ status = psa_get_key_from_slot( key, &slot, PSA_KEY_USAGE_DECRYPT, alg );
+ if( status != PSA_SUCCESS )
+ return( status );
+ if( ! PSA_KEY_TYPE_IS_KEYPAIR( slot->type ) )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+
+#if defined(MBEDCRYPTO_RSA_C)
+ if( slot->type == PSA_KEY_TYPE_RSA_KEYPAIR )
+ {
+ mbedcrypto_rsa_context *rsa = slot->data.rsa;
+ int ret;
+
+ if( input_length != mbedcrypto_rsa_get_len( rsa ) )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+
+#if defined(MBEDCRYPTO_PKCS1_V15)
+ if( alg == PSA_ALG_RSA_PKCS1V15_CRYPT )
+ {
+ ret = mbedcrypto_rsa_pkcs1_decrypt( rsa,
+ mbedcrypto_ctr_drbg_random,
+ &global_data.ctr_drbg,
+ MBEDCRYPTO_RSA_PRIVATE,
+ output_length,
+ input,
+ output,
+ output_size );
+ }
+ else
+#endif /* MBEDCRYPTO_PKCS1_V15 */
+#if defined(MBEDCRYPTO_PKCS1_V21)
+ if( PSA_ALG_IS_RSA_OAEP( alg ) )
+ {
+ psa_rsa_oaep_set_padding_mode( alg, rsa );
+ ret = mbedcrypto_rsa_rsaes_oaep_decrypt( rsa,
+ mbedcrypto_ctr_drbg_random,
+ &global_data.ctr_drbg,
+ MBEDCRYPTO_RSA_PRIVATE,
+ salt, salt_length,
+ output_length,
+ input,
+ output,
+ output_size );
+ }
+ else
+#endif /* MBEDCRYPTO_PKCS1_V21 */
+ {
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ }
+
+ return( mbedcrypto_to_psa_error( ret ) );
+ }
+ else
+#endif /* defined(MBEDCRYPTO_RSA_C) */
+ {
+ return( PSA_ERROR_NOT_SUPPORTED );
+ }
+}
+
+
+
+/****************************************************************/
+/* Symmetric cryptography */
+/****************************************************************/
+
+/* Initialize the cipher operation structure. Once this function has been
+ * called, psa_cipher_abort can run and will do the right thing. */
+static psa_status_t psa_cipher_init( psa_cipher_operation_t *operation,
+ psa_algorithm_t alg )
+{
+ if( ! PSA_ALG_IS_CIPHER( alg ) )
+ {
+ memset( operation, 0, sizeof( *operation ) );
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ }
+
+ operation->alg = alg;
+ operation->key_set = 0;
+ operation->iv_set = 0;
+ operation->iv_required = 1;
+ operation->iv_size = 0;
+ operation->block_size = 0;
+ mbedcrypto_cipher_init( &operation->ctx.cipher );
+ return( PSA_SUCCESS );
+}
+
+static psa_status_t psa_cipher_setup( psa_cipher_operation_t *operation,
+ psa_key_slot_t key,
+ psa_algorithm_t alg,
+ mbedcrypto_operation_t cipher_operation )
+{
+ int ret = MBEDCRYPTO_ERR_CIPHER_FEATURE_UNAVAILABLE;
+ psa_status_t status;
+ key_slot_t *slot;
+ size_t key_bits;
+ const mbedcrypto_cipher_info_t *cipher_info = NULL;
+ psa_key_usage_t usage = ( cipher_operation == MBEDCRYPTO_ENCRYPT ?
+ PSA_KEY_USAGE_ENCRYPT :
+ PSA_KEY_USAGE_DECRYPT );
+
+ status = psa_cipher_init( operation, alg );
+ if( status != PSA_SUCCESS )
+ return( status );
+
+ status = psa_get_key_from_slot( key, &slot, usage, alg);
+ if( status != PSA_SUCCESS )
+ return( status );
+ key_bits = psa_get_key_bits( slot );
+
+ cipher_info = mbedcrypto_cipher_info_from_psa( alg, slot->type, key_bits, NULL );
+ if( cipher_info == NULL )
+ return( PSA_ERROR_NOT_SUPPORTED );
+
+ ret = mbedcrypto_cipher_setup( &operation->ctx.cipher, cipher_info );
+ if( ret != 0 )
+ {
+ psa_cipher_abort( operation );
+ return( mbedcrypto_to_psa_error( ret ) );
+ }
+
+#if defined(MBEDCRYPTO_DES_C)
+ if( slot->type == PSA_KEY_TYPE_DES && key_bits == 128 )
+ {
+ /* Two-key Triple-DES is 3-key Triple-DES with K1=K3 */
+ unsigned char keys[24];
+ memcpy( keys, slot->data.raw.data, 16 );
+ memcpy( keys + 16, slot->data.raw.data, 8 );
+ ret = mbedcrypto_cipher_setkey( &operation->ctx.cipher,
+ keys,
+ 192, cipher_operation );
+ }
+ else
+#endif
+ {
+ ret = mbedcrypto_cipher_setkey( &operation->ctx.cipher,
+ slot->data.raw.data,
+ (int) key_bits, cipher_operation );
+ }
+ if( ret != 0 )
+ {
+ psa_cipher_abort( operation );
+ return( mbedcrypto_to_psa_error( ret ) );
+ }
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_WITH_PADDING)
+ if( ( alg & ~PSA_ALG_BLOCK_CIPHER_PADDING_MASK ) == PSA_ALG_CBC_BASE )
+ {
+ psa_algorithm_t padding_mode = alg & PSA_ALG_BLOCK_CIPHER_PADDING_MASK;
+ mbedcrypto_cipher_padding_t mode;
+
+ switch ( padding_mode )
+ {
+ case PSA_ALG_BLOCK_CIPHER_PAD_PKCS7:
+ mode = MBEDCRYPTO_PADDING_PKCS7;
+ break;
+ case PSA_ALG_BLOCK_CIPHER_PAD_NONE:
+ mode = MBEDCRYPTO_PADDING_NONE;
+ break;
+ default:
+ psa_cipher_abort( operation );
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ }
+ ret = mbedcrypto_cipher_set_padding_mode( &operation->ctx.cipher, mode );
+ if( ret != 0 )
+ {
+ psa_cipher_abort( operation );
+ return( mbedcrypto_to_psa_error( ret ) );
+ }
+ }
+#endif //MBEDCRYPTO_CIPHER_MODE_WITH_PADDING
+
+ operation->key_set = 1;
+ operation->block_size = ( PSA_ALG_IS_BLOCK_CIPHER( alg ) ?
+ PSA_BLOCK_CIPHER_BLOCK_SIZE( slot->type ) :
+ 1 );
+ if( PSA_ALG_IS_BLOCK_CIPHER( alg ) || alg == PSA_ALG_CTR )
+ {
+ operation->iv_size = PSA_BLOCK_CIPHER_BLOCK_SIZE( slot->type );
+ }
+
+ return( PSA_SUCCESS );
+}
+
+psa_status_t psa_cipher_encrypt_setup( psa_cipher_operation_t *operation,
+ psa_key_slot_t key,
+ psa_algorithm_t alg )
+{
+ return( psa_cipher_setup( operation, key, alg, MBEDCRYPTO_ENCRYPT ) );
+}
+
+psa_status_t psa_cipher_decrypt_setup( psa_cipher_operation_t *operation,
+ psa_key_slot_t key,
+ psa_algorithm_t alg )
+{
+ return( psa_cipher_setup( operation, key, alg, MBEDCRYPTO_DECRYPT ) );
+}
+
+psa_status_t psa_cipher_generate_iv( psa_cipher_operation_t *operation,
+ unsigned char *iv,
+ size_t iv_size,
+ size_t *iv_length )
+{
+ int ret = PSA_SUCCESS;
+ if( operation->iv_set || ! operation->iv_required )
+ return( PSA_ERROR_BAD_STATE );
+ if( iv_size < operation->iv_size )
+ {
+ ret = PSA_ERROR_BUFFER_TOO_SMALL;
+ goto exit;
+ }
+ ret = mbedcrypto_ctr_drbg_random( &global_data.ctr_drbg,
+ iv, operation->iv_size );
+ if( ret != 0 )
+ {
+ ret = mbedcrypto_to_psa_error( ret );
+ goto exit;
+ }
+
+ *iv_length = operation->iv_size;
+ ret = psa_cipher_set_iv( operation, iv, *iv_length );
+
+exit:
+ if( ret != PSA_SUCCESS )
+ psa_cipher_abort( operation );
+ return( ret );
+}
+
+psa_status_t psa_cipher_set_iv( psa_cipher_operation_t *operation,
+ const unsigned char *iv,
+ size_t iv_length )
+{
+ int ret = PSA_SUCCESS;
+ if( operation->iv_set || ! operation->iv_required )
+ return( PSA_ERROR_BAD_STATE );
+ if( iv_length != operation->iv_size )
+ {
+ psa_cipher_abort( operation );
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ }
+ ret = mbedcrypto_cipher_set_iv( &operation->ctx.cipher, iv, iv_length );
+ if( ret != 0 )
+ {
+ psa_cipher_abort( operation );
+ return( mbedcrypto_to_psa_error( ret ) );
+ }
+
+ operation->iv_set = 1;
+
+ return( PSA_SUCCESS );
+}
+
+psa_status_t psa_cipher_update( psa_cipher_operation_t *operation,
+ const uint8_t *input,
+ size_t input_length,
+ unsigned char *output,
+ size_t output_size,
+ size_t *output_length )
+{
+ int ret = MBEDCRYPTO_ERR_CIPHER_FEATURE_UNAVAILABLE;
+ size_t expected_output_size;
+ if( PSA_ALG_IS_BLOCK_CIPHER( operation->alg ) )
+ {
+ /* Take the unprocessed partial block left over from previous
+ * update calls, if any, plus the input to this call. Remove
+ * the last partial block, if any. You get the data that will be
+ * output in this call. */
+ expected_output_size =
+ ( operation->ctx.cipher.unprocessed_len + input_length )
+ / operation->block_size * operation->block_size;
+ }
+ else
+ {
+ expected_output_size = input_length;
+ }
+ if( output_size < expected_output_size )
+ return( PSA_ERROR_BUFFER_TOO_SMALL );
+
+ ret = mbedcrypto_cipher_update( &operation->ctx.cipher, input,
+ input_length, output, output_length );
+ if( ret != 0 )
+ {
+ psa_cipher_abort( operation );
+ return( mbedcrypto_to_psa_error( ret ) );
+ }
+
+ return( PSA_SUCCESS );
+}
+
+psa_status_t psa_cipher_finish( psa_cipher_operation_t *operation,
+ uint8_t *output,
+ size_t output_size,
+ size_t *output_length )
+{
+ psa_status_t status = PSA_ERROR_UNKNOWN_ERROR;
+ int cipher_ret = MBEDCRYPTO_ERR_CIPHER_FEATURE_UNAVAILABLE;
+ uint8_t temp_output_buffer[MBEDCRYPTO_MAX_BLOCK_LENGTH];
+
+ if( ! operation->key_set )
+ {
+ status = PSA_ERROR_BAD_STATE;
+ goto error;
+ }
+ if( operation->iv_required && ! operation->iv_set )
+ {
+ status = PSA_ERROR_BAD_STATE;
+ goto error;
+ }
+ if( operation->ctx.cipher.operation == MBEDCRYPTO_ENCRYPT &&
+ PSA_ALG_IS_BLOCK_CIPHER( operation->alg ) )
+ {
+ psa_algorithm_t padding_mode =
+ operation->alg & PSA_ALG_BLOCK_CIPHER_PADDING_MASK;
+ if( operation->ctx.cipher.unprocessed_len >= operation->block_size )
+ {
+ status = PSA_ERROR_TAMPERING_DETECTED;
+ goto error;
+ }
+ if( padding_mode == PSA_ALG_BLOCK_CIPHER_PAD_NONE )
+ {
+ if( operation->ctx.cipher.unprocessed_len != 0 )
+ {
+ status = PSA_ERROR_INVALID_ARGUMENT;
+ goto error;
+ }
+ }
+ }
+
+ cipher_ret = mbedcrypto_cipher_finish( &operation->ctx.cipher,
+ temp_output_buffer,
+ output_length );
+ if( cipher_ret != 0 )
+ {
+ status = mbedcrypto_to_psa_error( cipher_ret );
+ goto error;
+ }
+
+ if( *output_length == 0 )
+ ; /* Nothing to copy. Note that output may be NULL in this case. */
+ else if( output_size >= *output_length )
+ memcpy( output, temp_output_buffer, *output_length );
+ else
+ {
+ status = PSA_ERROR_BUFFER_TOO_SMALL;
+ goto error;
+ }
+
+ mbedcrypto_zeroize( temp_output_buffer, sizeof( temp_output_buffer ) );
+ status = psa_cipher_abort( operation );
+
+ return( status );
+
+error:
+
+ *output_length = 0;
+
+ mbedcrypto_zeroize( temp_output_buffer, sizeof( temp_output_buffer ) );
+ (void) psa_cipher_abort( operation );
+
+ return( status );
+}
+
+psa_status_t psa_cipher_abort( psa_cipher_operation_t *operation )
+{
+ if( operation->alg == 0 )
+ {
+ /* The object has (apparently) been initialized but it is not
+ * in use. It's ok to call abort on such an object, and there's
+ * nothing to do. */
+ return( PSA_SUCCESS );
+ }
+
+ /* Sanity check (shouldn't happen: operation->alg should
+ * always have been initialized to a valid value). */
+ if( ! PSA_ALG_IS_CIPHER( operation->alg ) )
+ return( PSA_ERROR_BAD_STATE );
+
+ mbedcrypto_cipher_free( &operation->ctx.cipher );
+
+ operation->alg = 0;
+ operation->key_set = 0;
+ operation->iv_set = 0;
+ operation->iv_size = 0;
+ operation->block_size = 0;
+ operation->iv_required = 0;
+
+ return( PSA_SUCCESS );
+}
+
+
+
+/****************************************************************/
+/* Key Policy */
+/****************************************************************/
+
+#if !defined(MBEDCRYPTO_PSA_CRYPTO_SPM)
+void psa_key_policy_init( psa_key_policy_t *policy )
+{
+ memset( policy, 0, sizeof( *policy ) );
+}
+
+void psa_key_policy_set_usage( psa_key_policy_t *policy,
+ psa_key_usage_t usage,
+ psa_algorithm_t alg )
+{
+ policy->usage = usage;
+ policy->alg = alg;
+}
+
+psa_key_usage_t psa_key_policy_get_usage( const psa_key_policy_t *policy )
+{
+ return( policy->usage );
+}
+
+psa_algorithm_t psa_key_policy_get_algorithm( const psa_key_policy_t *policy )
+{
+ return( policy->alg );
+}
+#endif /* !defined(MBEDCRYPTO_PSA_CRYPTO_SPM) */
+
+psa_status_t psa_set_key_policy( psa_key_slot_t key,
+ const psa_key_policy_t *policy )
+{
+ key_slot_t *slot;
+ psa_status_t status;
+
+ if( policy == NULL )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+
+ status = psa_get_empty_key_slot( key, &slot );
+ if( status != PSA_SUCCESS )
+ return( status );
+
+ if( ( policy->usage & ~( PSA_KEY_USAGE_EXPORT |
+ PSA_KEY_USAGE_ENCRYPT |
+ PSA_KEY_USAGE_DECRYPT |
+ PSA_KEY_USAGE_SIGN |
+ PSA_KEY_USAGE_VERIFY |
+ PSA_KEY_USAGE_DERIVE ) ) != 0 )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+
+ slot->policy = *policy;
+
+ return( PSA_SUCCESS );
+}
+
+psa_status_t psa_get_key_policy( psa_key_slot_t key,
+ psa_key_policy_t *policy )
+{
+ key_slot_t *slot;
+ psa_status_t status;
+
+ if( policy == NULL )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+
+ status = psa_get_key_slot( key, &slot );
+ if( status != PSA_SUCCESS )
+ return( status );
+
+ *policy = slot->policy;
+
+ return( PSA_SUCCESS );
+}
+
+
+
+/****************************************************************/
+/* Key Lifetime */
+/****************************************************************/
+
+psa_status_t psa_get_key_lifetime( psa_key_slot_t key,
+ psa_key_lifetime_t *lifetime )
+{
+ key_slot_t *slot;
+ psa_status_t status;
+
+ status = psa_get_key_slot( key, &slot );
+ if( status != PSA_SUCCESS )
+ return( status );
+
+ *lifetime = slot->lifetime;
+
+ return( PSA_SUCCESS );
+}
+
+psa_status_t psa_set_key_lifetime( psa_key_slot_t key,
+ psa_key_lifetime_t lifetime )
+{
+ key_slot_t *slot;
+ psa_status_t status;
+
+ if( lifetime != PSA_KEY_LIFETIME_VOLATILE &&
+ lifetime != PSA_KEY_LIFETIME_PERSISTENT &&
+ lifetime != PSA_KEY_LIFETIME_WRITE_ONCE)
+ return( PSA_ERROR_INVALID_ARGUMENT );
+
+ status = psa_get_empty_key_slot( key, &slot );
+ if( status != PSA_SUCCESS )
+ return( status );
+
+ if( lifetime != PSA_KEY_LIFETIME_VOLATILE )
+ return( PSA_ERROR_NOT_SUPPORTED );
+
+ slot->lifetime = lifetime;
+
+ return( PSA_SUCCESS );
+}
+
+
+
+/****************************************************************/
+/* AEAD */
+/****************************************************************/
+
+psa_status_t psa_aead_encrypt( psa_key_slot_t key,
+ psa_algorithm_t alg,
+ const uint8_t *nonce,
+ size_t nonce_length,
+ const uint8_t *additional_data,
+ size_t additional_data_length,
+ const uint8_t *plaintext,
+ size_t plaintext_length,
+ uint8_t *ciphertext,
+ size_t ciphertext_size,
+ size_t *ciphertext_length )
+{
+ int ret;
+ psa_status_t status;
+ key_slot_t *slot;
+ size_t key_bits;
+ uint8_t *tag;
+ size_t tag_length;
+ mbedcrypto_cipher_id_t cipher_id;
+ const mbedcrypto_cipher_info_t *cipher_info = NULL;
+
+ *ciphertext_length = 0;
+
+ status = psa_get_key_from_slot( key, &slot, PSA_KEY_USAGE_ENCRYPT, alg );
+ if( status != PSA_SUCCESS )
+ return( status );
+ key_bits = psa_get_key_bits( slot );
+
+ cipher_info = mbedcrypto_cipher_info_from_psa( alg, slot->type,
+ key_bits, &cipher_id );
+ if( cipher_info == NULL )
+ return( PSA_ERROR_NOT_SUPPORTED );
+
+ if( ( slot->type & PSA_KEY_TYPE_CATEGORY_MASK ) !=
+ PSA_KEY_TYPE_CATEGORY_SYMMETRIC )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+
+ if( alg == PSA_ALG_GCM )
+ {
+ mbedcrypto_gcm_context gcm;
+ tag_length = 16;
+
+ if( PSA_BLOCK_CIPHER_BLOCK_SIZE( slot->type ) != 16 )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+
+ //make sure we have place to hold the tag in the ciphertext buffer
+ if( ciphertext_size < ( plaintext_length + tag_length ) )
+ return( PSA_ERROR_BUFFER_TOO_SMALL );
+
+ //update the tag pointer to point to the end of the ciphertext_length
+ tag = ciphertext + plaintext_length;
+
+ mbedcrypto_gcm_init( &gcm );
+ ret = mbedcrypto_gcm_setkey( &gcm, cipher_id,
+ slot->data.raw.data,
+ (unsigned int) key_bits );
+ if( ret != 0 )
+ {
+ mbedcrypto_gcm_free( &gcm );
+ return( mbedcrypto_to_psa_error( ret ) );
+ }
+ ret = mbedcrypto_gcm_crypt_and_tag( &gcm, MBEDCRYPTO_GCM_ENCRYPT,
+ plaintext_length, nonce,
+ nonce_length, additional_data,
+ additional_data_length, plaintext,
+ ciphertext, tag_length, tag );
+ mbedcrypto_gcm_free( &gcm );
+ }
+ else if( alg == PSA_ALG_CCM )
+ {
+ mbedcrypto_ccm_context ccm;
+ tag_length = 16;
+
+ if( PSA_BLOCK_CIPHER_BLOCK_SIZE( slot->type ) != 16 )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+
+ if( nonce_length < 7 || nonce_length > 13 )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+
+ //make sure we have place to hold the tag in the ciphertext buffer
+ if( ciphertext_size < ( plaintext_length + tag_length ) )
+ return( PSA_ERROR_BUFFER_TOO_SMALL );
+
+ //update the tag pointer to point to the end of the ciphertext_length
+ tag = ciphertext + plaintext_length;
+
+ mbedcrypto_ccm_init( &ccm );
+ ret = mbedcrypto_ccm_setkey( &ccm, cipher_id,
+ slot->data.raw.data,
+ (unsigned int) key_bits );
+ if( ret != 0 )
+ {
+ mbedcrypto_ccm_free( &ccm );
+ return( mbedcrypto_to_psa_error( ret ) );
+ }
+ ret = mbedcrypto_ccm_encrypt_and_tag( &ccm, plaintext_length,
+ nonce, nonce_length,
+ additional_data,
+ additional_data_length,
+ plaintext, ciphertext,
+ tag, tag_length );
+ mbedcrypto_ccm_free( &ccm );
+ }
+ else
+ {
+ return( PSA_ERROR_NOT_SUPPORTED );
+ }
+
+ if( ret != 0 )
+ {
+ /* If ciphertext_size is 0 then ciphertext may be NULL and then the
+ * call to memset would have undefined behavior. */
+ if( ciphertext_size != 0 )
+ memset( ciphertext, 0, ciphertext_size );
+ return( mbedcrypto_to_psa_error( ret ) );
+ }
+
+ *ciphertext_length = plaintext_length + tag_length;
+ return( PSA_SUCCESS );
+}
+
+/* Locate the tag in a ciphertext buffer containing the encrypted data
+ * followed by the tag. Return the length of the part preceding the tag in
+ * *plaintext_length. This is the size of the plaintext in modes where
+ * the encrypted data has the same size as the plaintext, such as
+ * CCM and GCM. */
+static psa_status_t psa_aead_unpadded_locate_tag( size_t tag_length,
+ const uint8_t *ciphertext,
+ size_t ciphertext_length,
+ size_t plaintext_size,
+ const uint8_t **p_tag )
+{
+ size_t payload_length;
+ if( tag_length > ciphertext_length )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ payload_length = ciphertext_length - tag_length;
+ if( payload_length > plaintext_size )
+ return( PSA_ERROR_BUFFER_TOO_SMALL );
+ *p_tag = ciphertext + payload_length;
+ return( PSA_SUCCESS );
+}
+
+psa_status_t psa_aead_decrypt( psa_key_slot_t key,
+ psa_algorithm_t alg,
+ const uint8_t *nonce,
+ size_t nonce_length,
+ const uint8_t *additional_data,
+ size_t additional_data_length,
+ const uint8_t *ciphertext,
+ size_t ciphertext_length,
+ uint8_t *plaintext,
+ size_t plaintext_size,
+ size_t *plaintext_length )
+{
+ int ret;
+ psa_status_t status;
+ key_slot_t *slot;
+ size_t key_bits;
+ const uint8_t *tag;
+ size_t tag_length;
+ mbedcrypto_cipher_id_t cipher_id;
+ const mbedcrypto_cipher_info_t *cipher_info = NULL;
+
+ *plaintext_length = 0;
+
+ status = psa_get_key_from_slot( key, &slot, PSA_KEY_USAGE_DECRYPT, alg );
+ if( status != PSA_SUCCESS )
+ return( status );
+ key_bits = psa_get_key_bits( slot );
+
+ cipher_info = mbedcrypto_cipher_info_from_psa( alg, slot->type,
+ key_bits, &cipher_id );
+ if( cipher_info == NULL )
+ return( PSA_ERROR_NOT_SUPPORTED );
+
+ if( ( slot->type & PSA_KEY_TYPE_CATEGORY_MASK ) !=
+ PSA_KEY_TYPE_CATEGORY_SYMMETRIC )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+
+ if( alg == PSA_ALG_GCM )
+ {
+ mbedcrypto_gcm_context gcm;
+
+ tag_length = 16;
+ status = psa_aead_unpadded_locate_tag( tag_length,
+ ciphertext, ciphertext_length,
+ plaintext_size, &tag );
+ if( status != PSA_SUCCESS )
+ return( status );
+
+ mbedcrypto_gcm_init( &gcm );
+ ret = mbedcrypto_gcm_setkey( &gcm, cipher_id,
+ slot->data.raw.data,
+ (unsigned int) key_bits );
+ if( ret != 0 )
+ {
+ mbedcrypto_gcm_free( &gcm );
+ return( mbedcrypto_to_psa_error( ret ) );
+ }
+
+ ret = mbedcrypto_gcm_auth_decrypt( &gcm,
+ ciphertext_length - tag_length,
+ nonce, nonce_length,
+ additional_data,
+ additional_data_length,
+ tag, tag_length,
+ ciphertext, plaintext );
+ mbedcrypto_gcm_free( &gcm );
+ }
+ else if( alg == PSA_ALG_CCM )
+ {
+ mbedcrypto_ccm_context ccm;
+
+ if( nonce_length < 7 || nonce_length > 13 )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+
+ tag_length = 16;
+ status = psa_aead_unpadded_locate_tag( tag_length,
+ ciphertext, ciphertext_length,
+ plaintext_size, &tag );
+ if( status != PSA_SUCCESS )
+ return( status );
+
+ mbedcrypto_ccm_init( &ccm );
+ ret = mbedcrypto_ccm_setkey( &ccm, cipher_id,
+ slot->data.raw.data,
+ (unsigned int) key_bits );
+ if( ret != 0 )
+ {
+ mbedcrypto_ccm_free( &ccm );
+ return( mbedcrypto_to_psa_error( ret ) );
+ }
+ ret = mbedcrypto_ccm_auth_decrypt( &ccm, ciphertext_length - tag_length,
+ nonce, nonce_length,
+ additional_data,
+ additional_data_length,
+ ciphertext, plaintext,
+ tag, tag_length );
+ mbedcrypto_ccm_free( &ccm );
+ }
+ else
+ {
+ return( PSA_ERROR_NOT_SUPPORTED );
+ }
+
+ if( ret != 0 )
+ {
+ /* If plaintext_size is 0 then plaintext may be NULL and then the
+ * call to memset has undefined behavior. */
+ if( plaintext_size != 0 )
+ memset( plaintext, 0, plaintext_size );
+ }
+ else
+ *plaintext_length = ciphertext_length - tag_length;
+
+ return( mbedcrypto_to_psa_error( ret ) );
+}
+
+
+
+/****************************************************************/
+/* Generators */
+/****************************************************************/
+
+psa_status_t psa_generator_abort( psa_crypto_generator_t *generator )
+{
+ psa_status_t status = PSA_SUCCESS;
+ if( generator->alg == 0 )
+ {
+ /* The object has (apparently) been initialized but it is not
+ * in use. It's ok to call abort on such an object, and there's
+ * nothing to do. */
+ }
+ else
+#if defined(MBEDCRYPTO_MD_C)
+ if( PSA_ALG_IS_HKDF( generator->alg ) )
+ {
+ mbedcrypto_free( generator->ctx.hkdf.info );
+ status = psa_hmac_abort_internal( &generator->ctx.hkdf.hmac );
+ }
+ else
+#endif /* MBEDCRYPTO_MD_C */
+ {
+ status = PSA_ERROR_BAD_STATE;
+ }
+ memset( generator, 0, sizeof( *generator ) );
+ return( status );
+}
+
+
+psa_status_t psa_get_generator_capacity(const psa_crypto_generator_t *generator,
+ size_t *capacity)
+{
+ *capacity = generator->capacity;
+ return( PSA_SUCCESS );
+}
+
+#if defined(MBEDCRYPTO_MD_C)
+/* Read some bytes from an HKDF-based generator. This performs a chunk
+ * of the expand phase of the HKDF algorithm. */
+static psa_status_t psa_generator_hkdf_read( psa_hkdf_generator_t *hkdf,
+ psa_algorithm_t hash_alg,
+ uint8_t *output,
+ size_t output_length )
+{
+ uint8_t hash_length = PSA_HASH_SIZE( hash_alg );
+ psa_status_t status;
+
+ while( output_length != 0 )
+ {
+ /* Copy what remains of the current block */
+ uint8_t n = hash_length - hkdf->offset_in_block;
+ if( n > output_length )
+ n = (uint8_t) output_length;
+ memcpy( output, hkdf->output_block + hkdf->offset_in_block, n );
+ output += n;
+ output_length -= n;
+ hkdf->offset_in_block += n;
+ if( output_length == 0 )
+ break;
+ /* We can't be wanting more output after block 0xff, otherwise
+ * the capacity check in psa_generator_read() would have
+ * prevented this call. It could happen only if the generator
+ * object was corrupted or if this function is called directly
+ * inside the library. */
+ if( hkdf->block_number == 0xff )
+ return( PSA_ERROR_BAD_STATE );
+
+ /* We need a new block */
+ ++hkdf->block_number;
+ hkdf->offset_in_block = 0;
+ status = psa_hmac_setup_internal( &hkdf->hmac,
+ hkdf->prk, hash_length,
+ hash_alg );
+ if( status != PSA_SUCCESS )
+ return( status );
+ if( hkdf->block_number != 1 )
+ {
+ status = psa_hash_update( &hkdf->hmac.hash_ctx,
+ hkdf->output_block,
+ hash_length );
+ if( status != PSA_SUCCESS )
+ return( status );
+ }
+ status = psa_hash_update( &hkdf->hmac.hash_ctx,
+ hkdf->info,
+ hkdf->info_length );
+ if( status != PSA_SUCCESS )
+ return( status );
+ status = psa_hash_update( &hkdf->hmac.hash_ctx,
+ &hkdf->block_number, 1 );
+ if( status != PSA_SUCCESS )
+ return( status );
+ status = psa_hmac_finish_internal( &hkdf->hmac,
+ hkdf->output_block,
+ sizeof( hkdf->output_block ) );
+ if( status != PSA_SUCCESS )
+ return( status );
+ }
+
+ return( PSA_SUCCESS );
+}
+#endif /* MBEDCRYPTO_MD_C */
+
+psa_status_t psa_generator_read( psa_crypto_generator_t *generator,
+ uint8_t *output,
+ size_t output_length )
+{
+ psa_status_t status;
+
+ if( output_length > generator->capacity )
+ {
+ generator->capacity = 0;
+ /* Go through the error path to wipe all confidential data now
+ * that the generator object is useless. */
+ status = PSA_ERROR_INSUFFICIENT_CAPACITY;
+ goto exit;
+ }
+ if( output_length == 0 &&
+ generator->capacity == 0 && generator->alg == 0 )
+ {
+ /* Edge case: this is a blank or finished generator, and 0
+ * bytes were requested. The right error in this case could
+ * be either INSUFFICIENT_CAPACITY or BAD_STATE. Return
+ * INSUFFICIENT_CAPACITY, which is right for a finished
+ * generator, for consistency with the case when
+ * output_length > 0. */
+ return( PSA_ERROR_INSUFFICIENT_CAPACITY );
+ }
+ generator->capacity -= output_length;
+
+#if defined(MBEDCRYPTO_MD_C)
+ if( PSA_ALG_IS_HKDF( generator->alg ) )
+ {
+ psa_algorithm_t hash_alg = PSA_ALG_HKDF_GET_HASH( generator->alg );
+ status = psa_generator_hkdf_read( &generator->ctx.hkdf, hash_alg,
+ output, output_length );
+ }
+ else
+#endif /* MBEDCRYPTO_MD_C */
+ {
+ return( PSA_ERROR_BAD_STATE );
+ }
+
+exit:
+ if( status != PSA_SUCCESS )
+ {
+ psa_generator_abort( generator );
+ memset( output, '!', output_length );
+ }
+ return( status );
+}
+
+#if defined(MBEDCRYPTO_DES_C)
+static void psa_des_set_key_parity( uint8_t *data, size_t data_size )
+{
+ if( data_size >= 8 )
+ mbedcrypto_des_key_set_parity( data );
+ if( data_size >= 16 )
+ mbedcrypto_des_key_set_parity( data + 8 );
+ if( data_size >= 24 )
+ mbedcrypto_des_key_set_parity( data + 16 );
+}
+#endif /* MBEDCRYPTO_DES_C */
+
+psa_status_t psa_generator_import_key( psa_key_slot_t key,
+ psa_key_type_t type,
+ size_t bits,
+ psa_crypto_generator_t *generator )
+{
+ uint8_t *data = NULL;
+ size_t bytes = PSA_BITS_TO_BYTES( bits );
+ psa_status_t status;
+
+ if( ! key_type_is_raw_bytes( type ) )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ if( bits % 8 != 0 )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ data = mbedcrypto_calloc( 1, bytes );
+ if( data == NULL )
+ return( PSA_ERROR_INSUFFICIENT_MEMORY );
+
+ status = psa_generator_read( generator, data, bytes );
+ if( status != PSA_SUCCESS )
+ goto exit;
+#if defined(MBEDCRYPTO_DES_C)
+ if( type == PSA_KEY_TYPE_DES )
+ psa_des_set_key_parity( data, bytes );
+#endif /* MBEDCRYPTO_DES_C */
+ status = psa_import_key( key, type, data, bytes );
+
+exit:
+ mbedcrypto_free( data );
+ return( status );
+}
+
+
+
+/****************************************************************/
+/* Key derivation */
+/****************************************************************/
+
+/* Set up an HKDF-based generator. This is exactly the extract phase
+ * of the HKDF algorithm. */
+static psa_status_t psa_generator_hkdf_setup( psa_hkdf_generator_t *hkdf,
+ key_slot_t *slot,
+ psa_algorithm_t hash_alg,
+ const uint8_t *salt,
+ size_t salt_length,
+ const uint8_t *label,
+ size_t label_length )
+{
+ psa_status_t status;
+ status = psa_hmac_setup_internal( &hkdf->hmac,
+ salt, salt_length,
+ PSA_ALG_HMAC_HASH( hash_alg ) );
+ if( status != PSA_SUCCESS )
+ return( status );
+ status = psa_hash_update( &hkdf->hmac.hash_ctx,
+ slot->data.raw.data,
+ slot->data.raw.bytes );
+ if( status != PSA_SUCCESS )
+ return( status );
+ status = psa_hmac_finish_internal( &hkdf->hmac,
+ hkdf->prk,
+ sizeof( hkdf->prk ) );
+ if( status != PSA_SUCCESS )
+ return( status );
+ hkdf->offset_in_block = PSA_HASH_SIZE( hash_alg );
+ hkdf->block_number = 0;
+ hkdf->info_length = label_length;
+ if( label_length != 0 )
+ {
+ hkdf->info = mbedcrypto_calloc( 1, label_length );
+ if( hkdf->info == NULL )
+ return( PSA_ERROR_INSUFFICIENT_MEMORY );
+ memcpy( hkdf->info, label, label_length );
+ }
+ return( PSA_SUCCESS );
+}
+
+psa_status_t psa_key_derivation( psa_crypto_generator_t *generator,
+ psa_key_slot_t key,
+ psa_algorithm_t alg,
+ const uint8_t *salt,
+ size_t salt_length,
+ const uint8_t *label,
+ size_t label_length,
+ size_t capacity )
+{
+ key_slot_t *slot;
+ psa_status_t status;
+
+ if( generator->alg != 0 )
+ return( PSA_ERROR_BAD_STATE );
+
+ status = psa_get_key_from_slot( key, &slot, PSA_KEY_USAGE_DERIVE, alg );
+ if( status != PSA_SUCCESS )
+ return( status );
+ if( slot->type != PSA_KEY_TYPE_DERIVE )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+
+ if( ! PSA_ALG_IS_KEY_DERIVATION( alg ) )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+
+#if defined(MBEDCRYPTO_MD_C)
+ if( PSA_ALG_IS_HKDF( alg ) )
+ {
+ psa_algorithm_t hash_alg = PSA_ALG_HKDF_GET_HASH( alg );
+ size_t hash_size = PSA_HASH_SIZE( hash_alg );
+ if( hash_size == 0 )
+ return( PSA_ERROR_NOT_SUPPORTED );
+ if( capacity > 255 * hash_size )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ status = psa_generator_hkdf_setup( &generator->ctx.hkdf,
+ slot,
+ hash_alg,
+ salt, salt_length,
+ label, label_length );
+ }
+ else
+#endif
+ {
+ return( PSA_ERROR_NOT_SUPPORTED );
+ }
+
+ /* Set generator->alg even on failure so that abort knows what to do. */
+ generator->alg = alg;
+ if( status == PSA_SUCCESS )
+ generator->capacity = capacity;
+ else
+ psa_generator_abort( generator );
+ return( status );
+}
+
+
+
+/****************************************************************/
+/* Random generation */
+/****************************************************************/
+
+psa_status_t psa_generate_random( uint8_t *output,
+ size_t output_size )
+{
+ int ret = mbedcrypto_ctr_drbg_random( &global_data.ctr_drbg,
+ output, output_size );
+ return( mbedcrypto_to_psa_error( ret ) );
+}
+
+psa_status_t psa_generate_key( psa_key_slot_t key,
+ psa_key_type_t type,
+ size_t bits,
+ const void *extra,
+ size_t extra_size )
+{
+ key_slot_t *slot;
+ psa_status_t status;
+
+ if( extra == NULL && extra_size != 0 )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+
+ status = psa_get_empty_key_slot( key, &slot );
+ if( status != PSA_SUCCESS )
+ return( status );
+
+ if( key_type_is_raw_bytes( type ) )
+ {
+ status = prepare_raw_data_slot( type, bits, &slot->data.raw );
+ if( status != PSA_SUCCESS )
+ return( status );
+ status = psa_generate_random( slot->data.raw.data,
+ slot->data.raw.bytes );
+ if( status != PSA_SUCCESS )
+ {
+ mbedcrypto_free( slot->data.raw.data );
+ return( status );
+ }
+#if defined(MBEDCRYPTO_DES_C)
+ if( type == PSA_KEY_TYPE_DES )
+ psa_des_set_key_parity( slot->data.raw.data,
+ slot->data.raw.bytes );
+#endif /* MBEDCRYPTO_DES_C */
+ }
+ else
+
+#if defined(MBEDCRYPTO_RSA_C) && defined(MBEDCRYPTO_GENPRIME)
+ if ( type == PSA_KEY_TYPE_RSA_KEYPAIR )
+ {
+ mbedcrypto_rsa_context *rsa;
+ int ret;
+ int exponent = 65537;
+ if( bits > PSA_VENDOR_RSA_MAX_KEY_BITS )
+ return( PSA_ERROR_NOT_SUPPORTED );
+ if( extra != NULL )
+ {
+ const psa_generate_key_extra_rsa *p = extra;
+ if( extra_size != sizeof( *p ) )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+#if INT_MAX < 0xffffffff
+ /* Check that the uint32_t value passed by the caller fits
+ * in the range supported by this implementation. */
+ if( p->e > INT_MAX )
+ return( PSA_ERROR_NOT_SUPPORTED );
+#endif
+ exponent = p->e;
+ }
+ rsa = mbedcrypto_calloc( 1, sizeof( *rsa ) );
+ if( rsa == NULL )
+ return( PSA_ERROR_INSUFFICIENT_MEMORY );
+ mbedcrypto_rsa_init( rsa, MBEDCRYPTO_RSA_PKCS_V15, MBEDCRYPTO_MD_NONE );
+ ret = mbedcrypto_rsa_gen_key( rsa,
+ mbedcrypto_ctr_drbg_random,
+ &global_data.ctr_drbg,
+ (unsigned int) bits,
+ exponent );
+ if( ret != 0 )
+ {
+ mbedcrypto_rsa_free( rsa );
+ mbedcrypto_free( rsa );
+ return( mbedcrypto_to_psa_error( ret ) );
+ }
+ slot->data.rsa = rsa;
+ }
+ else
+#endif /* MBEDCRYPTO_RSA_C && MBEDCRYPTO_GENPRIME */
+
+#if defined(MBEDCRYPTO_ECP_C)
+ if ( PSA_KEY_TYPE_IS_ECC( type ) && PSA_KEY_TYPE_IS_KEYPAIR( type ) )
+ {
+ psa_ecc_curve_t curve = PSA_KEY_TYPE_GET_CURVE( type );
+ mbedcrypto_ecp_group_id grp_id = mbedcrypto_ecc_group_of_psa( curve );
+ const mbedcrypto_ecp_curve_info *curve_info =
+ mbedcrypto_ecp_curve_info_from_grp_id( grp_id );
+ mbedcrypto_ecp_keypair *ecp;
+ int ret;
+ if( extra != NULL )
+ return( PSA_ERROR_NOT_SUPPORTED );
+ if( grp_id == MBEDCRYPTO_ECP_DP_NONE || curve_info == NULL )
+ return( PSA_ERROR_NOT_SUPPORTED );
+ if( curve_info->bit_size != bits )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ ecp = mbedcrypto_calloc( 1, sizeof( *ecp ) );
+ if( ecp == NULL )
+ return( PSA_ERROR_INSUFFICIENT_MEMORY );
+ mbedcrypto_ecp_keypair_init( ecp );
+ ret = mbedcrypto_ecp_gen_key( grp_id, ecp,
+ mbedcrypto_ctr_drbg_random,
+ &global_data.ctr_drbg );
+ if( ret != 0 )
+ {
+ mbedcrypto_ecp_keypair_free( ecp );
+ mbedcrypto_free( ecp );
+ return( mbedcrypto_to_psa_error( ret ) );
+ }
+ slot->data.ecp = ecp;
+ }
+ else
+#endif /* MBEDCRYPTO_ECP_C */
+
+ return( PSA_ERROR_NOT_SUPPORTED );
+
+ slot->type = type;
+ return( PSA_SUCCESS );
+}
+
+
+/****************************************************************/
+/* Module setup */
+/****************************************************************/
+
+void mbedcrypto_psa_crypto_free( void )
+{
+ psa_key_slot_t key;
+ for( key = 1; key <= PSA_KEY_SLOT_COUNT; key++ )
+ psa_destroy_key( key );
+ mbedcrypto_ctr_drbg_free( &global_data.ctr_drbg );
+ mbedcrypto_entropy_free( &global_data.entropy );
+ mbedcrypto_zeroize( &global_data, sizeof( global_data ) );
+}
+
+psa_status_t psa_crypto_init( void )
+{
+ int ret;
+ const unsigned char drbg_seed[] = "PSA";
+
+ if( global_data.initialized != 0 )
+ return( PSA_SUCCESS );
+
+ mbedcrypto_zeroize( &global_data, sizeof( global_data ) );
+ mbedcrypto_entropy_init( &global_data.entropy );
+ mbedcrypto_ctr_drbg_init( &global_data.ctr_drbg );
+
+ ret = mbedcrypto_ctr_drbg_seed( &global_data.ctr_drbg,
+ mbedcrypto_entropy_func,
+ &global_data.entropy,
+ drbg_seed, sizeof( drbg_seed ) - 1 );
+ if( ret != 0 )
+ goto exit;
+
+ global_data.initialized = 1;
+
+exit:
+ if( ret != 0 )
+ mbedcrypto_psa_crypto_free( );
+ return( mbedcrypto_to_psa_error( ret ) );
+}
+
+#endif /* MBEDCRYPTO_PSA_CRYPTO_C */
diff --git a/library/ripemd160.c b/library/ripemd160.c
new file mode 100644
index 0000000..fc86887
--- /dev/null
+++ b/library/ripemd160.c
@@ -0,0 +1,552 @@
+/*
+ * RIPE MD-160 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 Crypto (https://tls.mbed.org)
+ */
+
+/*
+ * The RIPEMD-160 algorithm was designed by RIPE in 1996
+ * http://homes.esat.kuleuven.be/~bosselae/mbedcrypto_ripemd160.html
+ * http://ehash.iaik.tugraz.at/wiki/RIPEMD-160
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_RIPEMD160_C)
+
+#include "mbedcrypto/ripemd160.h"
+#include "mbedcrypto/platform_util.h"
+
+#include <string.h>
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#include <stdio.h>
+#define mbedcrypto_printf printf
+#endif /* MBEDCRYPTO_PLATFORM_C */
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#if !defined(MBEDCRYPTO_RIPEMD160_ALT)
+
+/*
+ * 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
+
+void mbedcrypto_ripemd160_init( mbedcrypto_ripemd160_context *ctx )
+{
+ memset( ctx, 0, sizeof( mbedcrypto_ripemd160_context ) );
+}
+
+void mbedcrypto_ripemd160_free( mbedcrypto_ripemd160_context *ctx )
+{
+ if( ctx == NULL )
+ return;
+
+ mbedcrypto_platform_zeroize( ctx, sizeof( mbedcrypto_ripemd160_context ) );
+}
+
+void mbedcrypto_ripemd160_clone( mbedcrypto_ripemd160_context *dst,
+ const mbedcrypto_ripemd160_context *src )
+{
+ *dst = *src;
+}
+
+/*
+ * RIPEMD-160 context setup
+ */
+int mbedcrypto_ripemd160_starts_ret( mbedcrypto_ripemd160_context *ctx )
+{
+ ctx->total[0] = 0;
+ ctx->total[1] = 0;
+
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xEFCDAB89;
+ ctx->state[2] = 0x98BADCFE;
+ ctx->state[3] = 0x10325476;
+ ctx->state[4] = 0xC3D2E1F0;
+
+ return( 0 );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_ripemd160_starts( mbedcrypto_ripemd160_context *ctx )
+{
+ mbedcrypto_ripemd160_starts_ret( ctx );
+}
+#endif
+
+#if !defined(MBEDCRYPTO_RIPEMD160_PROCESS_ALT)
+/*
+ * Process one block
+ */
+int mbedcrypto_internal_ripemd160_process( mbedcrypto_ripemd160_context *ctx,
+ const unsigned char data[64] )
+{
+ uint32_t A, B, C, D, E, Ap, Bp, Cp, Dp, Ep, X[16];
+
+ GET_UINT32_LE( X[ 0], data, 0 );
+ GET_UINT32_LE( X[ 1], data, 4 );
+ GET_UINT32_LE( X[ 2], data, 8 );
+ GET_UINT32_LE( X[ 3], data, 12 );
+ GET_UINT32_LE( X[ 4], data, 16 );
+ GET_UINT32_LE( X[ 5], data, 20 );
+ GET_UINT32_LE( X[ 6], data, 24 );
+ GET_UINT32_LE( X[ 7], data, 28 );
+ GET_UINT32_LE( X[ 8], data, 32 );
+ GET_UINT32_LE( X[ 9], data, 36 );
+ GET_UINT32_LE( X[10], data, 40 );
+ GET_UINT32_LE( X[11], data, 44 );
+ GET_UINT32_LE( X[12], data, 48 );
+ GET_UINT32_LE( X[13], data, 52 );
+ GET_UINT32_LE( X[14], data, 56 );
+ GET_UINT32_LE( X[15], data, 60 );
+
+ A = Ap = ctx->state[0];
+ B = Bp = ctx->state[1];
+ C = Cp = ctx->state[2];
+ D = Dp = ctx->state[3];
+ E = Ep = ctx->state[4];
+
+#define F1( x, y, z ) ( x ^ y ^ z )
+#define F2( x, y, z ) ( ( x & y ) | ( ~x & z ) )
+#define F3( x, y, z ) ( ( x | ~y ) ^ z )
+#define F4( x, y, z ) ( ( x & z ) | ( y & ~z ) )
+#define F5( x, y, z ) ( x ^ ( y | ~z ) )
+
+#define S( x, n ) ( ( x << n ) | ( x >> (32 - n) ) )
+
+#define P( a, b, c, d, e, r, s, f, k ) \
+ a += f( b, c, d ) + X[r] + k; \
+ a = S( a, s ) + e; \
+ c = S( c, 10 );
+
+#define P2( a, b, c, d, e, r, s, rp, sp ) \
+ P( a, b, c, d, e, r, s, F, K ); \
+ P( a ## p, b ## p, c ## p, d ## p, e ## p, rp, sp, Fp, Kp );
+
+#define F F1
+#define K 0x00000000
+#define Fp F5
+#define Kp 0x50A28BE6
+ P2( A, B, C, D, E, 0, 11, 5, 8 );
+ P2( E, A, B, C, D, 1, 14, 14, 9 );
+ P2( D, E, A, B, C, 2, 15, 7, 9 );
+ P2( C, D, E, A, B, 3, 12, 0, 11 );
+ P2( B, C, D, E, A, 4, 5, 9, 13 );
+ P2( A, B, C, D, E, 5, 8, 2, 15 );
+ P2( E, A, B, C, D, 6, 7, 11, 15 );
+ P2( D, E, A, B, C, 7, 9, 4, 5 );
+ P2( C, D, E, A, B, 8, 11, 13, 7 );
+ P2( B, C, D, E, A, 9, 13, 6, 7 );
+ P2( A, B, C, D, E, 10, 14, 15, 8 );
+ P2( E, A, B, C, D, 11, 15, 8, 11 );
+ P2( D, E, A, B, C, 12, 6, 1, 14 );
+ P2( C, D, E, A, B, 13, 7, 10, 14 );
+ P2( B, C, D, E, A, 14, 9, 3, 12 );
+ P2( A, B, C, D, E, 15, 8, 12, 6 );
+#undef F
+#undef K
+#undef Fp
+#undef Kp
+
+#define F F2
+#define K 0x5A827999
+#define Fp F4
+#define Kp 0x5C4DD124
+ P2( E, A, B, C, D, 7, 7, 6, 9 );
+ P2( D, E, A, B, C, 4, 6, 11, 13 );
+ P2( C, D, E, A, B, 13, 8, 3, 15 );
+ P2( B, C, D, E, A, 1, 13, 7, 7 );
+ P2( A, B, C, D, E, 10, 11, 0, 12 );
+ P2( E, A, B, C, D, 6, 9, 13, 8 );
+ P2( D, E, A, B, C, 15, 7, 5, 9 );
+ P2( C, D, E, A, B, 3, 15, 10, 11 );
+ P2( B, C, D, E, A, 12, 7, 14, 7 );
+ P2( A, B, C, D, E, 0, 12, 15, 7 );
+ P2( E, A, B, C, D, 9, 15, 8, 12 );
+ P2( D, E, A, B, C, 5, 9, 12, 7 );
+ P2( C, D, E, A, B, 2, 11, 4, 6 );
+ P2( B, C, D, E, A, 14, 7, 9, 15 );
+ P2( A, B, C, D, E, 11, 13, 1, 13 );
+ P2( E, A, B, C, D, 8, 12, 2, 11 );
+#undef F
+#undef K
+#undef Fp
+#undef Kp
+
+#define F F3
+#define K 0x6ED9EBA1
+#define Fp F3
+#define Kp 0x6D703EF3
+ P2( D, E, A, B, C, 3, 11, 15, 9 );
+ P2( C, D, E, A, B, 10, 13, 5, 7 );
+ P2( B, C, D, E, A, 14, 6, 1, 15 );
+ P2( A, B, C, D, E, 4, 7, 3, 11 );
+ P2( E, A, B, C, D, 9, 14, 7, 8 );
+ P2( D, E, A, B, C, 15, 9, 14, 6 );
+ P2( C, D, E, A, B, 8, 13, 6, 6 );
+ P2( B, C, D, E, A, 1, 15, 9, 14 );
+ P2( A, B, C, D, E, 2, 14, 11, 12 );
+ P2( E, A, B, C, D, 7, 8, 8, 13 );
+ P2( D, E, A, B, C, 0, 13, 12, 5 );
+ P2( C, D, E, A, B, 6, 6, 2, 14 );
+ P2( B, C, D, E, A, 13, 5, 10, 13 );
+ P2( A, B, C, D, E, 11, 12, 0, 13 );
+ P2( E, A, B, C, D, 5, 7, 4, 7 );
+ P2( D, E, A, B, C, 12, 5, 13, 5 );
+#undef F
+#undef K
+#undef Fp
+#undef Kp
+
+#define F F4
+#define K 0x8F1BBCDC
+#define Fp F2
+#define Kp 0x7A6D76E9
+ P2( C, D, E, A, B, 1, 11, 8, 15 );
+ P2( B, C, D, E, A, 9, 12, 6, 5 );
+ P2( A, B, C, D, E, 11, 14, 4, 8 );
+ P2( E, A, B, C, D, 10, 15, 1, 11 );
+ P2( D, E, A, B, C, 0, 14, 3, 14 );
+ P2( C, D, E, A, B, 8, 15, 11, 14 );
+ P2( B, C, D, E, A, 12, 9, 15, 6 );
+ P2( A, B, C, D, E, 4, 8, 0, 14 );
+ P2( E, A, B, C, D, 13, 9, 5, 6 );
+ P2( D, E, A, B, C, 3, 14, 12, 9 );
+ P2( C, D, E, A, B, 7, 5, 2, 12 );
+ P2( B, C, D, E, A, 15, 6, 13, 9 );
+ P2( A, B, C, D, E, 14, 8, 9, 12 );
+ P2( E, A, B, C, D, 5, 6, 7, 5 );
+ P2( D, E, A, B, C, 6, 5, 10, 15 );
+ P2( C, D, E, A, B, 2, 12, 14, 8 );
+#undef F
+#undef K
+#undef Fp
+#undef Kp
+
+#define F F5
+#define K 0xA953FD4E
+#define Fp F1
+#define Kp 0x00000000
+ P2( B, C, D, E, A, 4, 9, 12, 8 );
+ P2( A, B, C, D, E, 0, 15, 15, 5 );
+ P2( E, A, B, C, D, 5, 5, 10, 12 );
+ P2( D, E, A, B, C, 9, 11, 4, 9 );
+ P2( C, D, E, A, B, 7, 6, 1, 12 );
+ P2( B, C, D, E, A, 12, 8, 5, 5 );
+ P2( A, B, C, D, E, 2, 13, 8, 14 );
+ P2( E, A, B, C, D, 10, 12, 7, 6 );
+ P2( D, E, A, B, C, 14, 5, 6, 8 );
+ P2( C, D, E, A, B, 1, 12, 2, 13 );
+ P2( B, C, D, E, A, 3, 13, 13, 6 );
+ P2( A, B, C, D, E, 8, 14, 14, 5 );
+ P2( E, A, B, C, D, 11, 11, 0, 15 );
+ P2( D, E, A, B, C, 6, 8, 3, 13 );
+ P2( C, D, E, A, B, 15, 5, 9, 11 );
+ P2( B, C, D, E, A, 13, 6, 11, 11 );
+#undef F
+#undef K
+#undef Fp
+#undef Kp
+
+ C = ctx->state[1] + C + Dp;
+ ctx->state[1] = ctx->state[2] + D + Ep;
+ ctx->state[2] = ctx->state[3] + E + Ap;
+ ctx->state[3] = ctx->state[4] + A + Bp;
+ ctx->state[4] = ctx->state[0] + B + Cp;
+ ctx->state[0] = C;
+
+ return( 0 );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_ripemd160_process( mbedcrypto_ripemd160_context *ctx,
+ const unsigned char data[64] )
+{
+ mbedcrypto_internal_ripemd160_process( ctx, data );
+}
+#endif
+#endif /* !MBEDCRYPTO_RIPEMD160_PROCESS_ALT */
+
+/*
+ * RIPEMD-160 process buffer
+ */
+int mbedcrypto_ripemd160_update_ret( mbedcrypto_ripemd160_context *ctx,
+ const unsigned char *input,
+ size_t ilen )
+{
+ int ret;
+ size_t fill;
+ uint32_t left;
+
+ if( ilen == 0 )
+ return( 0 );
+
+ left = ctx->total[0] & 0x3F;
+ fill = 64 - left;
+
+ ctx->total[0] += (uint32_t) ilen;
+ ctx->total[0] &= 0xFFFFFFFF;
+
+ if( ctx->total[0] < (uint32_t) ilen )
+ ctx->total[1]++;
+
+ if( left && ilen >= fill )
+ {
+ memcpy( (void *) (ctx->buffer + left), input, fill );
+
+ if( ( ret = mbedcrypto_internal_ripemd160_process( ctx, ctx->buffer ) ) != 0 )
+ return( ret );
+
+ input += fill;
+ ilen -= fill;
+ left = 0;
+ }
+
+ while( ilen >= 64 )
+ {
+ if( ( ret = mbedcrypto_internal_ripemd160_process( ctx, input ) ) != 0 )
+ return( ret );
+
+ input += 64;
+ ilen -= 64;
+ }
+
+ if( ilen > 0 )
+ {
+ memcpy( (void *) (ctx->buffer + left), input, ilen );
+ }
+
+ return( 0 );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_ripemd160_update( mbedcrypto_ripemd160_context *ctx,
+ const unsigned char *input,
+ size_t ilen )
+{
+ mbedcrypto_ripemd160_update_ret( ctx, input, ilen );
+}
+#endif
+
+static const unsigned char ripemd160_padding[64] =
+{
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * RIPEMD-160 final digest
+ */
+int mbedcrypto_ripemd160_finish_ret( mbedcrypto_ripemd160_context *ctx,
+ unsigned char output[20] )
+{
+ int ret;
+ uint32_t last, padn;
+ uint32_t high, low;
+ unsigned char msglen[8];
+
+ high = ( ctx->total[0] >> 29 )
+ | ( ctx->total[1] << 3 );
+ low = ( ctx->total[0] << 3 );
+
+ PUT_UINT32_LE( low, msglen, 0 );
+ PUT_UINT32_LE( high, msglen, 4 );
+
+ last = ctx->total[0] & 0x3F;
+ padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
+
+ ret = mbedcrypto_ripemd160_update_ret( ctx, ripemd160_padding, padn );
+ if( ret != 0 )
+ return( ret );
+
+ ret = mbedcrypto_ripemd160_update_ret( ctx, msglen, 8 );
+ if( ret != 0 )
+ return( ret );
+
+ PUT_UINT32_LE( ctx->state[0], output, 0 );
+ PUT_UINT32_LE( ctx->state[1], output, 4 );
+ PUT_UINT32_LE( ctx->state[2], output, 8 );
+ PUT_UINT32_LE( ctx->state[3], output, 12 );
+ PUT_UINT32_LE( ctx->state[4], output, 16 );
+
+ return( 0 );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_ripemd160_finish( mbedcrypto_ripemd160_context *ctx,
+ unsigned char output[20] )
+{
+ mbedcrypto_ripemd160_finish_ret( ctx, output );
+}
+#endif
+
+#endif /* ! MBEDCRYPTO_RIPEMD160_ALT */
+
+/*
+ * output = RIPEMD-160( input buffer )
+ */
+int mbedcrypto_ripemd160_ret( const unsigned char *input,
+ size_t ilen,
+ unsigned char output[20] )
+{
+ int ret;
+ mbedcrypto_ripemd160_context ctx;
+
+ mbedcrypto_ripemd160_init( &ctx );
+
+ if( ( ret = mbedcrypto_ripemd160_starts_ret( &ctx ) ) != 0 )
+ goto exit;
+
+ if( ( ret = mbedcrypto_ripemd160_update_ret( &ctx, input, ilen ) ) != 0 )
+ goto exit;
+
+ if( ( ret = mbedcrypto_ripemd160_finish_ret( &ctx, output ) ) != 0 )
+ goto exit;
+
+exit:
+ mbedcrypto_ripemd160_free( &ctx );
+
+ return( ret );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_ripemd160( const unsigned char *input,
+ size_t ilen,
+ unsigned char output[20] )
+{
+ mbedcrypto_ripemd160_ret( input, ilen, output );
+}
+#endif
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+/*
+ * Test vectors from the RIPEMD-160 paper and
+ * http://homes.esat.kuleuven.be/~bosselae/mbedcrypto_ripemd160.html#HMAC
+ */
+#define TESTS 8
+static const unsigned char ripemd160_test_str[TESTS][81] =
+{
+ { "" },
+ { "a" },
+ { "abc" },
+ { "message digest" },
+ { "abcdefghijklmnopqrstuvwxyz" },
+ { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" },
+ { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" },
+ { "12345678901234567890123456789012345678901234567890123456789012"
+ "345678901234567890" },
+};
+
+static const size_t ripemd160_test_strlen[TESTS] =
+{
+ 0, 1, 3, 14, 26, 56, 62, 80
+};
+
+static const unsigned char ripemd160_test_md[TESTS][20] =
+{
+ { 0x9c, 0x11, 0x85, 0xa5, 0xc5, 0xe9, 0xfc, 0x54, 0x61, 0x28,
+ 0x08, 0x97, 0x7e, 0xe8, 0xf5, 0x48, 0xb2, 0x25, 0x8d, 0x31 },
+ { 0x0b, 0xdc, 0x9d, 0x2d, 0x25, 0x6b, 0x3e, 0xe9, 0xda, 0xae,
+ 0x34, 0x7b, 0xe6, 0xf4, 0xdc, 0x83, 0x5a, 0x46, 0x7f, 0xfe },
+ { 0x8e, 0xb2, 0x08, 0xf7, 0xe0, 0x5d, 0x98, 0x7a, 0x9b, 0x04,
+ 0x4a, 0x8e, 0x98, 0xc6, 0xb0, 0x87, 0xf1, 0x5a, 0x0b, 0xfc },
+ { 0x5d, 0x06, 0x89, 0xef, 0x49, 0xd2, 0xfa, 0xe5, 0x72, 0xb8,
+ 0x81, 0xb1, 0x23, 0xa8, 0x5f, 0xfa, 0x21, 0x59, 0x5f, 0x36 },
+ { 0xf7, 0x1c, 0x27, 0x10, 0x9c, 0x69, 0x2c, 0x1b, 0x56, 0xbb,
+ 0xdc, 0xeb, 0x5b, 0x9d, 0x28, 0x65, 0xb3, 0x70, 0x8d, 0xbc },
+ { 0x12, 0xa0, 0x53, 0x38, 0x4a, 0x9c, 0x0c, 0x88, 0xe4, 0x05,
+ 0xa0, 0x6c, 0x27, 0xdc, 0xf4, 0x9a, 0xda, 0x62, 0xeb, 0x2b },
+ { 0xb0, 0xe2, 0x0b, 0x6e, 0x31, 0x16, 0x64, 0x02, 0x86, 0xed,
+ 0x3a, 0x87, 0xa5, 0x71, 0x30, 0x79, 0xb2, 0x1f, 0x51, 0x89 },
+ { 0x9b, 0x75, 0x2e, 0x45, 0x57, 0x3d, 0x4b, 0x39, 0xf4, 0xdb,
+ 0xd3, 0x32, 0x3c, 0xab, 0x82, 0xbf, 0x63, 0x32, 0x6b, 0xfb },
+};
+
+/*
+ * Checkup routine
+ */
+int mbedcrypto_ripemd160_self_test( int verbose )
+{
+ int i, ret = 0;
+ unsigned char output[20];
+
+ memset( output, 0, sizeof output );
+
+ for( i = 0; i < TESTS; i++ )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( " RIPEMD-160 test #%d: ", i + 1 );
+
+ ret = mbedcrypto_ripemd160_ret( ripemd160_test_str[i],
+ ripemd160_test_strlen[i], output );
+ if( ret != 0 )
+ goto fail;
+
+ if( memcmp( output, ripemd160_test_md[i], 20 ) != 0 )
+ {
+ ret = 1;
+ goto fail;
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "\n" );
+
+ return( 0 );
+
+fail:
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+
+ return( ret );
+}
+
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#endif /* MBEDCRYPTO_RIPEMD160_C */
diff --git a/library/rsa.c b/library/rsa.c
new file mode 100644
index 0000000..698d1b1
--- /dev/null
+++ b/library/rsa.c
@@ -0,0 +1,2411 @@
+/*
+ * The RSA public-key cryptosystem
+ *
+ * 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 Crypto (https://tls.mbed.org)
+ */
+
+/*
+ * The following sources were referenced in the design of this implementation
+ * of the RSA algorithm:
+ *
+ * [1] A method for obtaining digital signatures and public-key cryptosystems
+ * R Rivest, A Shamir, and L Adleman
+ * http://people.csail.mit.edu/rivest/pubs.html#RSA78
+ *
+ * [2] Handbook of Applied Cryptography - 1997, Chapter 8
+ * Menezes, van Oorschot and Vanstone
+ *
+ * [3] Malware Guard Extension: Using SGX to Conceal Cache Attacks
+ * Michael Schwarz, Samuel Weiser, Daniel Gruss, Clémentine Maurice and
+ * Stefan Mangard
+ * https://arxiv.org/abs/1702.08719v2
+ *
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_RSA_C)
+
+#include "mbedcrypto/rsa.h"
+#include "mbedcrypto/rsa_internal.h"
+#include "mbedcrypto/oid.h"
+#include "mbedcrypto/platform_util.h"
+
+#include <string.h>
+
+#if defined(MBEDCRYPTO_PKCS1_V21)
+#include "mbedcrypto/md.h"
+#endif
+
+#if defined(MBEDCRYPTO_PKCS1_V15) && !defined(__OpenBSD__)
+#include <stdlib.h>
+#endif
+
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#include <stdio.h>
+#define mbedcrypto_printf printf
+#define mbedcrypto_calloc calloc
+#define mbedcrypto_free free
+#endif
+
+#if !defined(MBEDCRYPTO_RSA_ALT)
+
+#if defined(MBEDCRYPTO_PKCS1_V15)
+/* constant-time buffer comparison */
+static inline int mbedcrypto_safer_memcmp( const void *a, const void *b, size_t n )
+{
+ size_t i;
+ const unsigned char *A = (const unsigned char *) a;
+ const unsigned char *B = (const unsigned char *) b;
+ unsigned char diff = 0;
+
+ for( i = 0; i < n; i++ )
+ diff |= A[i] ^ B[i];
+
+ return( diff );
+}
+#endif /* MBEDCRYPTO_PKCS1_V15 */
+
+int mbedcrypto_rsa_import( mbedcrypto_rsa_context *ctx,
+ const mbedcrypto_mpi *N,
+ const mbedcrypto_mpi *P, const mbedcrypto_mpi *Q,
+ const mbedcrypto_mpi *D, const mbedcrypto_mpi *E )
+{
+ int ret;
+
+ if( ( N != NULL && ( ret = mbedcrypto_mpi_copy( &ctx->N, N ) ) != 0 ) ||
+ ( P != NULL && ( ret = mbedcrypto_mpi_copy( &ctx->P, P ) ) != 0 ) ||
+ ( Q != NULL && ( ret = mbedcrypto_mpi_copy( &ctx->Q, Q ) ) != 0 ) ||
+ ( D != NULL && ( ret = mbedcrypto_mpi_copy( &ctx->D, D ) ) != 0 ) ||
+ ( E != NULL && ( ret = mbedcrypto_mpi_copy( &ctx->E, E ) ) != 0 ) )
+ {
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA + ret );
+ }
+
+ if( N != NULL )
+ ctx->len = mbedcrypto_mpi_size( &ctx->N );
+
+ return( 0 );
+}
+
+int mbedcrypto_rsa_import_raw( mbedcrypto_rsa_context *ctx,
+ unsigned char const *N, size_t N_len,
+ unsigned char const *P, size_t P_len,
+ unsigned char const *Q, size_t Q_len,
+ unsigned char const *D, size_t D_len,
+ unsigned char const *E, size_t E_len )
+{
+ int ret = 0;
+
+ if( N != NULL )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_binary( &ctx->N, N, N_len ) );
+ ctx->len = mbedcrypto_mpi_size( &ctx->N );
+ }
+
+ if( P != NULL )
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_binary( &ctx->P, P, P_len ) );
+
+ if( Q != NULL )
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_binary( &ctx->Q, Q, Q_len ) );
+
+ if( D != NULL )
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_binary( &ctx->D, D, D_len ) );
+
+ if( E != NULL )
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_binary( &ctx->E, E, E_len ) );
+
+cleanup:
+
+ if( ret != 0 )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA + ret );
+
+ return( 0 );
+}
+
+/*
+ * Checks whether the context fields are set in such a way
+ * that the RSA primitives will be able to execute without error.
+ * It does *not* make guarantees for consistency of the parameters.
+ */
+static int rsa_check_context( mbedcrypto_rsa_context const *ctx, int is_priv,
+ int blinding_needed )
+{
+#if !defined(MBEDCRYPTO_RSA_NO_CRT)
+ /* blinding_needed is only used for NO_CRT to decide whether
+ * P,Q need to be present or not. */
+ ((void) blinding_needed);
+#endif
+
+ if( ctx->len != mbedcrypto_mpi_size( &ctx->N ) ||
+ ctx->len > MBEDCRYPTO_MPI_MAX_SIZE )
+ {
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+ }
+
+ /*
+ * 1. Modular exponentiation needs positive, odd moduli.
+ */
+
+ /* Modular exponentiation wrt. N is always used for
+ * RSA public key operations. */
+ if( mbedcrypto_mpi_cmp_int( &ctx->N, 0 ) <= 0 ||
+ mbedcrypto_mpi_get_bit( &ctx->N, 0 ) == 0 )
+ {
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+ }
+
+#if !defined(MBEDCRYPTO_RSA_NO_CRT)
+ /* Modular exponentiation for P and Q is only
+ * used for private key operations and if CRT
+ * is used. */
+ if( is_priv &&
+ ( mbedcrypto_mpi_cmp_int( &ctx->P, 0 ) <= 0 ||
+ mbedcrypto_mpi_get_bit( &ctx->P, 0 ) == 0 ||
+ mbedcrypto_mpi_cmp_int( &ctx->Q, 0 ) <= 0 ||
+ mbedcrypto_mpi_get_bit( &ctx->Q, 0 ) == 0 ) )
+ {
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+ }
+#endif /* !MBEDCRYPTO_RSA_NO_CRT */
+
+ /*
+ * 2. Exponents must be positive
+ */
+
+ /* Always need E for public key operations */
+ if( mbedcrypto_mpi_cmp_int( &ctx->E, 0 ) <= 0 )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+#if defined(MBEDCRYPTO_RSA_NO_CRT)
+ /* For private key operations, use D or DP & DQ
+ * as (unblinded) exponents. */
+ if( is_priv && mbedcrypto_mpi_cmp_int( &ctx->D, 0 ) <= 0 )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+#else
+ if( is_priv &&
+ ( mbedcrypto_mpi_cmp_int( &ctx->DP, 0 ) <= 0 ||
+ mbedcrypto_mpi_cmp_int( &ctx->DQ, 0 ) <= 0 ) )
+ {
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+ }
+#endif /* MBEDCRYPTO_RSA_NO_CRT */
+
+ /* Blinding shouldn't make exponents negative either,
+ * so check that P, Q >= 1 if that hasn't yet been
+ * done as part of 1. */
+#if defined(MBEDCRYPTO_RSA_NO_CRT)
+ if( is_priv && blinding_needed &&
+ ( mbedcrypto_mpi_cmp_int( &ctx->P, 0 ) <= 0 ||
+ mbedcrypto_mpi_cmp_int( &ctx->Q, 0 ) <= 0 ) )
+ {
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+ }
+#endif
+
+ /* It wouldn't lead to an error if it wasn't satisfied,
+ * but check for QP >= 1 nonetheless. */
+#if !defined(MBEDCRYPTO_RSA_NO_CRT)
+ if( is_priv &&
+ mbedcrypto_mpi_cmp_int( &ctx->QP, 0 ) <= 0 )
+ {
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+ }
+#endif
+
+ return( 0 );
+}
+
+int mbedcrypto_rsa_complete( mbedcrypto_rsa_context *ctx )
+{
+ int ret = 0;
+
+ const int have_N = ( mbedcrypto_mpi_cmp_int( &ctx->N, 0 ) != 0 );
+ const int have_P = ( mbedcrypto_mpi_cmp_int( &ctx->P, 0 ) != 0 );
+ const int have_Q = ( mbedcrypto_mpi_cmp_int( &ctx->Q, 0 ) != 0 );
+ const int have_D = ( mbedcrypto_mpi_cmp_int( &ctx->D, 0 ) != 0 );
+ const int have_E = ( mbedcrypto_mpi_cmp_int( &ctx->E, 0 ) != 0 );
+
+ /*
+ * Check whether provided parameters are enough
+ * to deduce all others. The following incomplete
+ * parameter sets for private keys are supported:
+ *
+ * (1) P, Q missing.
+ * (2) D and potentially N missing.
+ *
+ */
+
+ const int n_missing = have_P && have_Q && have_D && have_E;
+ const int pq_missing = have_N && !have_P && !have_Q && have_D && have_E;
+ const int d_missing = have_P && have_Q && !have_D && have_E;
+ const int is_pub = have_N && !have_P && !have_Q && !have_D && have_E;
+
+ /* These three alternatives are mutually exclusive */
+ const int is_priv = n_missing || pq_missing || d_missing;
+
+ if( !is_priv && !is_pub )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ /*
+ * Step 1: Deduce N if P, Q are provided.
+ */
+
+ if( !have_N && have_P && have_Q )
+ {
+ if( ( ret = mbedcrypto_mpi_mul_mpi( &ctx->N, &ctx->P,
+ &ctx->Q ) ) != 0 )
+ {
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA + ret );
+ }
+
+ ctx->len = mbedcrypto_mpi_size( &ctx->N );
+ }
+
+ /*
+ * Step 2: Deduce and verify all remaining core parameters.
+ */
+
+ if( pq_missing )
+ {
+ ret = mbedcrypto_rsa_deduce_primes( &ctx->N, &ctx->E, &ctx->D,
+ &ctx->P, &ctx->Q );
+ if( ret != 0 )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA + ret );
+
+ }
+ else if( d_missing )
+ {
+ if( ( ret = mbedcrypto_rsa_deduce_private_exponent( &ctx->P,
+ &ctx->Q,
+ &ctx->E,
+ &ctx->D ) ) != 0 )
+ {
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA + ret );
+ }
+ }
+
+ /*
+ * Step 3: Deduce all additional parameters specific
+ * to our current RSA implementation.
+ */
+
+#if !defined(MBEDCRYPTO_RSA_NO_CRT)
+ if( is_priv )
+ {
+ ret = mbedcrypto_rsa_deduce_crt( &ctx->P, &ctx->Q, &ctx->D,
+ &ctx->DP, &ctx->DQ, &ctx->QP );
+ if( ret != 0 )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA + ret );
+ }
+#endif /* MBEDCRYPTO_RSA_NO_CRT */
+
+ /*
+ * Step 3: Basic sanity checks
+ */
+
+ return( rsa_check_context( ctx, is_priv, 1 ) );
+}
+
+int mbedcrypto_rsa_export_raw( const mbedcrypto_rsa_context *ctx,
+ unsigned char *N, size_t N_len,
+ unsigned char *P, size_t P_len,
+ unsigned char *Q, size_t Q_len,
+ unsigned char *D, size_t D_len,
+ unsigned char *E, size_t E_len )
+{
+ int ret = 0;
+
+ /* Check if key is private or public */
+ const int is_priv =
+ mbedcrypto_mpi_cmp_int( &ctx->N, 0 ) != 0 &&
+ mbedcrypto_mpi_cmp_int( &ctx->P, 0 ) != 0 &&
+ mbedcrypto_mpi_cmp_int( &ctx->Q, 0 ) != 0 &&
+ mbedcrypto_mpi_cmp_int( &ctx->D, 0 ) != 0 &&
+ mbedcrypto_mpi_cmp_int( &ctx->E, 0 ) != 0;
+
+ if( !is_priv )
+ {
+ /* If we're trying to export private parameters for a public key,
+ * something must be wrong. */
+ if( P != NULL || Q != NULL || D != NULL )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ }
+
+ if( N != NULL )
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_write_binary( &ctx->N, N, N_len ) );
+
+ if( P != NULL )
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_write_binary( &ctx->P, P, P_len ) );
+
+ if( Q != NULL )
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_write_binary( &ctx->Q, Q, Q_len ) );
+
+ if( D != NULL )
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_write_binary( &ctx->D, D, D_len ) );
+
+ if( E != NULL )
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_write_binary( &ctx->E, E, E_len ) );
+
+cleanup:
+
+ return( ret );
+}
+
+int mbedcrypto_rsa_export( const mbedcrypto_rsa_context *ctx,
+ mbedcrypto_mpi *N, mbedcrypto_mpi *P, mbedcrypto_mpi *Q,
+ mbedcrypto_mpi *D, mbedcrypto_mpi *E )
+{
+ int ret;
+
+ /* Check if key is private or public */
+ int is_priv =
+ mbedcrypto_mpi_cmp_int( &ctx->N, 0 ) != 0 &&
+ mbedcrypto_mpi_cmp_int( &ctx->P, 0 ) != 0 &&
+ mbedcrypto_mpi_cmp_int( &ctx->Q, 0 ) != 0 &&
+ mbedcrypto_mpi_cmp_int( &ctx->D, 0 ) != 0 &&
+ mbedcrypto_mpi_cmp_int( &ctx->E, 0 ) != 0;
+
+ if( !is_priv )
+ {
+ /* If we're trying to export private parameters for a public key,
+ * something must be wrong. */
+ if( P != NULL || Q != NULL || D != NULL )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ }
+
+ /* Export all requested core parameters. */
+
+ if( ( N != NULL && ( ret = mbedcrypto_mpi_copy( N, &ctx->N ) ) != 0 ) ||
+ ( P != NULL && ( ret = mbedcrypto_mpi_copy( P, &ctx->P ) ) != 0 ) ||
+ ( Q != NULL && ( ret = mbedcrypto_mpi_copy( Q, &ctx->Q ) ) != 0 ) ||
+ ( D != NULL && ( ret = mbedcrypto_mpi_copy( D, &ctx->D ) ) != 0 ) ||
+ ( E != NULL && ( ret = mbedcrypto_mpi_copy( E, &ctx->E ) ) != 0 ) )
+ {
+ return( ret );
+ }
+
+ return( 0 );
+}
+
+/*
+ * Export CRT parameters
+ * This must also be implemented if CRT is not used, for being able to
+ * write DER encoded RSA keys. The helper function mbedcrypto_rsa_deduce_crt
+ * can be used in this case.
+ */
+int mbedcrypto_rsa_export_crt( const mbedcrypto_rsa_context *ctx,
+ mbedcrypto_mpi *DP, mbedcrypto_mpi *DQ, mbedcrypto_mpi *QP )
+{
+ int ret;
+
+ /* Check if key is private or public */
+ int is_priv =
+ mbedcrypto_mpi_cmp_int( &ctx->N, 0 ) != 0 &&
+ mbedcrypto_mpi_cmp_int( &ctx->P, 0 ) != 0 &&
+ mbedcrypto_mpi_cmp_int( &ctx->Q, 0 ) != 0 &&
+ mbedcrypto_mpi_cmp_int( &ctx->D, 0 ) != 0 &&
+ mbedcrypto_mpi_cmp_int( &ctx->E, 0 ) != 0;
+
+ if( !is_priv )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+#if !defined(MBEDCRYPTO_RSA_NO_CRT)
+ /* Export all requested blinding parameters. */
+ if( ( DP != NULL && ( ret = mbedcrypto_mpi_copy( DP, &ctx->DP ) ) != 0 ) ||
+ ( DQ != NULL && ( ret = mbedcrypto_mpi_copy( DQ, &ctx->DQ ) ) != 0 ) ||
+ ( QP != NULL && ( ret = mbedcrypto_mpi_copy( QP, &ctx->QP ) ) != 0 ) )
+ {
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA + ret );
+ }
+#else
+ if( ( ret = mbedcrypto_rsa_deduce_crt( &ctx->P, &ctx->Q, &ctx->D,
+ DP, DQ, QP ) ) != 0 )
+ {
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA + ret );
+ }
+#endif
+
+ return( 0 );
+}
+
+/*
+ * Initialize an RSA context
+ */
+void mbedcrypto_rsa_init( mbedcrypto_rsa_context *ctx,
+ int padding,
+ int hash_id )
+{
+ memset( ctx, 0, sizeof( mbedcrypto_rsa_context ) );
+
+ mbedcrypto_rsa_set_padding( ctx, padding, hash_id );
+
+#if defined(MBEDCRYPTO_THREADING_C)
+ mbedcrypto_mutex_init( &ctx->mutex );
+#endif
+}
+
+/*
+ * Set padding for an existing RSA context
+ */
+void mbedcrypto_rsa_set_padding( mbedcrypto_rsa_context *ctx, int padding, int hash_id )
+{
+ ctx->padding = padding;
+ ctx->hash_id = hash_id;
+}
+
+/*
+ * Get length in bytes of RSA modulus
+ */
+size_t mbedcrypto_rsa_get_len( const mbedcrypto_rsa_context *ctx )
+{
+ return( ctx->len );
+}
+
+/*
+ * Get length in bits of RSA modulus
+ */
+size_t mbedcrypto_rsa_get_bitlen( const mbedcrypto_rsa_context *ctx )
+{
+ return( mbedcrypto_mpi_bitlen( &ctx->N ) );
+}
+
+
+#if defined(MBEDCRYPTO_GENPRIME)
+
+/*
+ * Generate an RSA keypair
+ *
+ * This generation method follows the RSA key pair generation procedure of
+ * FIPS 186-4 if 2^16 < exponent < 2^256 and nbits = 2048 or nbits = 3072.
+ */
+int mbedcrypto_rsa_gen_key( mbedcrypto_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ unsigned int nbits, int exponent )
+{
+ int ret;
+ mbedcrypto_mpi H, G, L;
+
+ if( f_rng == NULL || nbits < 128 || exponent < 3 )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ if( nbits % 2 )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ mbedcrypto_mpi_init( &H );
+ mbedcrypto_mpi_init( &G );
+ mbedcrypto_mpi_init( &L );
+
+ /*
+ * find primes P and Q with Q < P so that:
+ * 1. |P-Q| > 2^( nbits / 2 - 100 )
+ * 2. GCD( E, (P-1)*(Q-1) ) == 1
+ * 3. E^-1 mod LCM(P-1, Q-1) > 2^( nbits / 2 )
+ */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_lset( &ctx->E, exponent ) );
+
+ do
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_gen_prime( &ctx->P, nbits >> 1, 0,
+ f_rng, p_rng ) );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_gen_prime( &ctx->Q, nbits >> 1, 0,
+ f_rng, p_rng ) );
+
+ /* make sure the difference between p and q is not too small (FIPS 186-4 §B.3.3 step 5.4) */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &H, &ctx->P, &ctx->Q ) );
+ if( mbedcrypto_mpi_bitlen( &H ) <= ( ( nbits >= 200 ) ? ( ( nbits >> 1 ) - 99 ) : 0 ) )
+ continue;
+
+ /* not required by any standards, but some users rely on the fact that P > Q */
+ if( H.s < 0 )
+ mbedcrypto_mpi_swap( &ctx->P, &ctx->Q );
+
+ /* Temporarily replace P,Q by P-1, Q-1 */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_int( &ctx->P, &ctx->P, 1 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_int( &ctx->Q, &ctx->Q, 1 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &H, &ctx->P, &ctx->Q ) );
+
+ /* check GCD( E, (P-1)*(Q-1) ) == 1 (FIPS 186-4 §B.3.1 criterion 2(a)) */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_gcd( &G, &ctx->E, &H ) );
+ if( mbedcrypto_mpi_cmp_int( &G, 1 ) != 0 )
+ continue;
+
+ /* compute smallest possible D = E^-1 mod LCM(P-1, Q-1) (FIPS 186-4 §B.3.1 criterion 3(b)) */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_gcd( &G, &ctx->P, &ctx->Q ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_div_mpi( &L, NULL, &H, &G ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_inv_mod( &ctx->D, &ctx->E, &L ) );
+
+ if( mbedcrypto_mpi_bitlen( &ctx->D ) <= ( ( nbits + 1 ) / 2 ) ) // (FIPS 186-4 §B.3.1 criterion 3(a))
+ continue;
+
+ break;
+ }
+ while( 1 );
+
+ /* Restore P,Q */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_int( &ctx->P, &ctx->P, 1 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_int( &ctx->Q, &ctx->Q, 1 ) );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &ctx->N, &ctx->P, &ctx->Q ) );
+
+ ctx->len = mbedcrypto_mpi_size( &ctx->N );
+
+#if !defined(MBEDCRYPTO_RSA_NO_CRT)
+ /*
+ * DP = D mod (P - 1)
+ * DQ = D mod (Q - 1)
+ * QP = Q^-1 mod P
+ */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_rsa_deduce_crt( &ctx->P, &ctx->Q, &ctx->D,
+ &ctx->DP, &ctx->DQ, &ctx->QP ) );
+#endif /* MBEDCRYPTO_RSA_NO_CRT */
+
+ /* Double-check */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_rsa_check_privkey( ctx ) );
+
+cleanup:
+
+ mbedcrypto_mpi_free( &H );
+ mbedcrypto_mpi_free( &G );
+ mbedcrypto_mpi_free( &L );
+
+ if( ret != 0 )
+ {
+ mbedcrypto_rsa_free( ctx );
+ return( MBEDCRYPTO_ERR_RSA_KEY_GEN_FAILED + ret );
+ }
+
+ return( 0 );
+}
+
+#endif /* MBEDCRYPTO_GENPRIME */
+
+/*
+ * Check a public RSA key
+ */
+int mbedcrypto_rsa_check_pubkey( const mbedcrypto_rsa_context *ctx )
+{
+ if( rsa_check_context( ctx, 0 /* public */, 0 /* no blinding */ ) != 0 )
+ return( MBEDCRYPTO_ERR_RSA_KEY_CHECK_FAILED );
+
+ if( mbedcrypto_mpi_bitlen( &ctx->N ) < 128 )
+ {
+ return( MBEDCRYPTO_ERR_RSA_KEY_CHECK_FAILED );
+ }
+
+ if( mbedcrypto_mpi_get_bit( &ctx->E, 0 ) == 0 ||
+ mbedcrypto_mpi_bitlen( &ctx->E ) < 2 ||
+ mbedcrypto_mpi_cmp_mpi( &ctx->E, &ctx->N ) >= 0 )
+ {
+ return( MBEDCRYPTO_ERR_RSA_KEY_CHECK_FAILED );
+ }
+
+ return( 0 );
+}
+
+/*
+ * Check for the consistency of all fields in an RSA private key context
+ */
+int mbedcrypto_rsa_check_privkey( const mbedcrypto_rsa_context *ctx )
+{
+ if( mbedcrypto_rsa_check_pubkey( ctx ) != 0 ||
+ rsa_check_context( ctx, 1 /* private */, 1 /* blinding */ ) != 0 )
+ {
+ return( MBEDCRYPTO_ERR_RSA_KEY_CHECK_FAILED );
+ }
+
+ if( mbedcrypto_rsa_validate_params( &ctx->N, &ctx->P, &ctx->Q,
+ &ctx->D, &ctx->E, NULL, NULL ) != 0 )
+ {
+ return( MBEDCRYPTO_ERR_RSA_KEY_CHECK_FAILED );
+ }
+
+#if !defined(MBEDCRYPTO_RSA_NO_CRT)
+ else if( mbedcrypto_rsa_validate_crt( &ctx->P, &ctx->Q, &ctx->D,
+ &ctx->DP, &ctx->DQ, &ctx->QP ) != 0 )
+ {
+ return( MBEDCRYPTO_ERR_RSA_KEY_CHECK_FAILED );
+ }
+#endif
+
+ return( 0 );
+}
+
+/*
+ * Check if contexts holding a public and private key match
+ */
+int mbedcrypto_rsa_check_pub_priv( const mbedcrypto_rsa_context *pub,
+ const mbedcrypto_rsa_context *prv )
+{
+ if( mbedcrypto_rsa_check_pubkey( pub ) != 0 ||
+ mbedcrypto_rsa_check_privkey( prv ) != 0 )
+ {
+ return( MBEDCRYPTO_ERR_RSA_KEY_CHECK_FAILED );
+ }
+
+ if( mbedcrypto_mpi_cmp_mpi( &pub->N, &prv->N ) != 0 ||
+ mbedcrypto_mpi_cmp_mpi( &pub->E, &prv->E ) != 0 )
+ {
+ return( MBEDCRYPTO_ERR_RSA_KEY_CHECK_FAILED );
+ }
+
+ return( 0 );
+}
+
+/*
+ * Do an RSA public key operation
+ */
+int mbedcrypto_rsa_public( mbedcrypto_rsa_context *ctx,
+ const unsigned char *input,
+ unsigned char *output )
+{
+ int ret;
+ size_t olen;
+ mbedcrypto_mpi T;
+
+ if( rsa_check_context( ctx, 0 /* public */, 0 /* no blinding */ ) )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ mbedcrypto_mpi_init( &T );
+
+#if defined(MBEDCRYPTO_THREADING_C)
+ if( ( ret = mbedcrypto_mutex_lock( &ctx->mutex ) ) != 0 )
+ return( ret );
+#endif
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_binary( &T, input, ctx->len ) );
+
+ if( mbedcrypto_mpi_cmp_mpi( &T, &ctx->N ) >= 0 )
+ {
+ ret = MBEDCRYPTO_ERR_MPI_BAD_INPUT_DATA;
+ goto cleanup;
+ }
+
+ olen = ctx->len;
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_exp_mod( &T, &T, &ctx->E, &ctx->N, &ctx->RN ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_write_binary( &T, output, olen ) );
+
+cleanup:
+#if defined(MBEDCRYPTO_THREADING_C)
+ if( mbedcrypto_mutex_unlock( &ctx->mutex ) != 0 )
+ return( MBEDCRYPTO_ERR_THREADING_MUTEX_ERROR );
+#endif
+
+ mbedcrypto_mpi_free( &T );
+
+ if( ret != 0 )
+ return( MBEDCRYPTO_ERR_RSA_PUBLIC_FAILED + ret );
+
+ return( 0 );
+}
+
+/*
+ * Generate or update blinding values, see section 10 of:
+ * KOCHER, Paul C. Timing attacks on implementations of Diffie-Hellman, RSA,
+ * DSS, and other systems. In : Advances in Cryptology-CRYPTO'96. Springer
+ * Berlin Heidelberg, 1996. p. 104-113.
+ */
+static int rsa_prepare_blinding( mbedcrypto_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
+{
+ int ret, count = 0;
+
+ if( ctx->Vf.p != NULL )
+ {
+ /* We already have blinding values, just update them by squaring */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &ctx->Vi, &ctx->Vi, &ctx->Vi ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mod_mpi( &ctx->Vi, &ctx->Vi, &ctx->N ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &ctx->Vf, &ctx->Vf, &ctx->Vf ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mod_mpi( &ctx->Vf, &ctx->Vf, &ctx->N ) );
+
+ goto cleanup;
+ }
+
+ /* Unblinding value: Vf = random number, invertible mod N */
+ do {
+ if( count++ > 10 )
+ return( MBEDCRYPTO_ERR_RSA_RNG_FAILED );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_fill_random( &ctx->Vf, ctx->len - 1, f_rng, p_rng ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_gcd( &ctx->Vi, &ctx->Vf, &ctx->N ) );
+ } while( mbedcrypto_mpi_cmp_int( &ctx->Vi, 1 ) != 0 );
+
+ /* Blinding value: Vi = Vf^(-e) mod N */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_inv_mod( &ctx->Vi, &ctx->Vf, &ctx->N ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_exp_mod( &ctx->Vi, &ctx->Vi, &ctx->E, &ctx->N, &ctx->RN ) );
+
+
+cleanup:
+ return( ret );
+}
+
+/*
+ * Exponent blinding supposed to prevent side-channel attacks using multiple
+ * traces of measurements to recover the RSA key. The more collisions are there,
+ * the more bits of the key can be recovered. See [3].
+ *
+ * Collecting n collisions with m bit long blinding value requires 2^(m-m/n)
+ * observations on avarage.
+ *
+ * For example with 28 byte blinding to achieve 2 collisions the adversary has
+ * to make 2^112 observations on avarage.
+ *
+ * (With the currently (as of 2017 April) known best algorithms breaking 2048
+ * bit RSA requires approximately as much time as trying out 2^112 random keys.
+ * Thus in this sense with 28 byte blinding the security is not reduced by
+ * side-channel attacks like the one in [3])
+ *
+ * This countermeasure does not help if the key recovery is possible with a
+ * single trace.
+ */
+#define RSA_EXPONENT_BLINDING 28
+
+/*
+ * Do an RSA private key operation
+ */
+int mbedcrypto_rsa_private( mbedcrypto_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ const unsigned char *input,
+ unsigned char *output )
+{
+ int ret;
+ size_t olen;
+
+ /* Temporary holding the result */
+ mbedcrypto_mpi T;
+
+ /* Temporaries holding P-1, Q-1 and the
+ * exponent blinding factor, respectively. */
+ mbedcrypto_mpi P1, Q1, R;
+
+#if !defined(MBEDCRYPTO_RSA_NO_CRT)
+ /* Temporaries holding the results mod p resp. mod q. */
+ mbedcrypto_mpi TP, TQ;
+
+ /* Temporaries holding the blinded exponents for
+ * the mod p resp. mod q computation (if used). */
+ mbedcrypto_mpi DP_blind, DQ_blind;
+
+ /* Pointers to actual exponents to be used - either the unblinded
+ * or the blinded ones, depending on the presence of a PRNG. */
+ mbedcrypto_mpi *DP = &ctx->DP;
+ mbedcrypto_mpi *DQ = &ctx->DQ;
+#else
+ /* Temporary holding the blinded exponent (if used). */
+ mbedcrypto_mpi D_blind;
+
+ /* Pointer to actual exponent to be used - either the unblinded
+ * or the blinded one, depending on the presence of a PRNG. */
+ mbedcrypto_mpi *D = &ctx->D;
+#endif /* MBEDCRYPTO_RSA_NO_CRT */
+
+ /* Temporaries holding the initial input and the double
+ * checked result; should be the same in the end. */
+ mbedcrypto_mpi I, C;
+
+ if( rsa_check_context( ctx, 1 /* private key checks */,
+ f_rng != NULL /* blinding y/n */ ) != 0 )
+ {
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+ }
+
+#if defined(MBEDCRYPTO_THREADING_C)
+ if( ( ret = mbedcrypto_mutex_lock( &ctx->mutex ) ) != 0 )
+ return( ret );
+#endif
+
+ /* MPI Initialization */
+ mbedcrypto_mpi_init( &T );
+
+ mbedcrypto_mpi_init( &P1 );
+ mbedcrypto_mpi_init( &Q1 );
+ mbedcrypto_mpi_init( &R );
+
+ if( f_rng != NULL )
+ {
+#if defined(MBEDCRYPTO_RSA_NO_CRT)
+ mbedcrypto_mpi_init( &D_blind );
+#else
+ mbedcrypto_mpi_init( &DP_blind );
+ mbedcrypto_mpi_init( &DQ_blind );
+#endif
+ }
+
+#if !defined(MBEDCRYPTO_RSA_NO_CRT)
+ mbedcrypto_mpi_init( &TP ); mbedcrypto_mpi_init( &TQ );
+#endif
+
+ mbedcrypto_mpi_init( &I );
+ mbedcrypto_mpi_init( &C );
+
+ /* End of MPI initialization */
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_binary( &T, input, ctx->len ) );
+ if( mbedcrypto_mpi_cmp_mpi( &T, &ctx->N ) >= 0 )
+ {
+ ret = MBEDCRYPTO_ERR_MPI_BAD_INPUT_DATA;
+ goto cleanup;
+ }
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &I, &T ) );
+
+ if( f_rng != NULL )
+ {
+ /*
+ * Blinding
+ * T = T * Vi mod N
+ */
+ MBEDCRYPTO_MPI_CHK( rsa_prepare_blinding( ctx, f_rng, p_rng ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &T, &T, &ctx->Vi ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mod_mpi( &T, &T, &ctx->N ) );
+
+ /*
+ * Exponent blinding
+ */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_int( &P1, &ctx->P, 1 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_int( &Q1, &ctx->Q, 1 ) );
+
+#if defined(MBEDCRYPTO_RSA_NO_CRT)
+ /*
+ * D_blind = ( P - 1 ) * ( Q - 1 ) * R + D
+ */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_fill_random( &R, RSA_EXPONENT_BLINDING,
+ f_rng, p_rng ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &D_blind, &P1, &Q1 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &D_blind, &D_blind, &R ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_mpi( &D_blind, &D_blind, &ctx->D ) );
+
+ D = &D_blind;
+#else
+ /*
+ * DP_blind = ( P - 1 ) * R + DP
+ */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_fill_random( &R, RSA_EXPONENT_BLINDING,
+ f_rng, p_rng ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &DP_blind, &P1, &R ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_mpi( &DP_blind, &DP_blind,
+ &ctx->DP ) );
+
+ DP = &DP_blind;
+
+ /*
+ * DQ_blind = ( Q - 1 ) * R + DQ
+ */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_fill_random( &R, RSA_EXPONENT_BLINDING,
+ f_rng, p_rng ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &DQ_blind, &Q1, &R ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_mpi( &DQ_blind, &DQ_blind,
+ &ctx->DQ ) );
+
+ DQ = &DQ_blind;
+#endif /* MBEDCRYPTO_RSA_NO_CRT */
+ }
+
+#if defined(MBEDCRYPTO_RSA_NO_CRT)
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_exp_mod( &T, &T, D, &ctx->N, &ctx->RN ) );
+#else
+ /*
+ * Faster decryption using the CRT
+ *
+ * TP = input ^ dP mod P
+ * TQ = input ^ dQ mod Q
+ */
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_exp_mod( &TP, &T, DP, &ctx->P, &ctx->RP ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_exp_mod( &TQ, &T, DQ, &ctx->Q, &ctx->RQ ) );
+
+ /*
+ * T = (TP - TQ) * (Q^-1 mod P) mod P
+ */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &T, &TP, &TQ ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &TP, &T, &ctx->QP ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mod_mpi( &T, &TP, &ctx->P ) );
+
+ /*
+ * T = TQ + T * Q
+ */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &TP, &T, &ctx->Q ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_mpi( &T, &TQ, &TP ) );
+#endif /* MBEDCRYPTO_RSA_NO_CRT */
+
+ if( f_rng != NULL )
+ {
+ /*
+ * Unblind
+ * T = T * Vf mod N
+ */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &T, &T, &ctx->Vf ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mod_mpi( &T, &T, &ctx->N ) );
+ }
+
+ /* Verify the result to prevent glitching attacks. */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_exp_mod( &C, &T, &ctx->E,
+ &ctx->N, &ctx->RN ) );
+ if( mbedcrypto_mpi_cmp_mpi( &C, &I ) != 0 )
+ {
+ ret = MBEDCRYPTO_ERR_RSA_VERIFY_FAILED;
+ goto cleanup;
+ }
+
+ olen = ctx->len;
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_write_binary( &T, output, olen ) );
+
+cleanup:
+#if defined(MBEDCRYPTO_THREADING_C)
+ if( mbedcrypto_mutex_unlock( &ctx->mutex ) != 0 )
+ return( MBEDCRYPTO_ERR_THREADING_MUTEX_ERROR );
+#endif
+
+ mbedcrypto_mpi_free( &P1 );
+ mbedcrypto_mpi_free( &Q1 );
+ mbedcrypto_mpi_free( &R );
+
+ if( f_rng != NULL )
+ {
+#if defined(MBEDCRYPTO_RSA_NO_CRT)
+ mbedcrypto_mpi_free( &D_blind );
+#else
+ mbedcrypto_mpi_free( &DP_blind );
+ mbedcrypto_mpi_free( &DQ_blind );
+#endif
+ }
+
+ mbedcrypto_mpi_free( &T );
+
+#if !defined(MBEDCRYPTO_RSA_NO_CRT)
+ mbedcrypto_mpi_free( &TP ); mbedcrypto_mpi_free( &TQ );
+#endif
+
+ mbedcrypto_mpi_free( &C );
+ mbedcrypto_mpi_free( &I );
+
+ if( ret != 0 )
+ return( MBEDCRYPTO_ERR_RSA_PRIVATE_FAILED + ret );
+
+ return( 0 );
+}
+
+#if defined(MBEDCRYPTO_PKCS1_V21)
+/**
+ * Generate and apply the MGF1 operation (from PKCS#1 v2.1) to a buffer.
+ *
+ * \param dst buffer to mask
+ * \param dlen length of destination buffer
+ * \param src source of the mask generation
+ * \param slen length of the source buffer
+ * \param md_ctx message digest context to use
+ */
+static int mgf_mask( unsigned char *dst, size_t dlen, unsigned char *src,
+ size_t slen, mbedcrypto_md_context_t *md_ctx )
+{
+ unsigned char mask[MBEDCRYPTO_MD_MAX_SIZE];
+ unsigned char counter[4];
+ unsigned char *p;
+ unsigned int hlen;
+ size_t i, use_len;
+ int ret = 0;
+
+ memset( mask, 0, MBEDCRYPTO_MD_MAX_SIZE );
+ memset( counter, 0, 4 );
+
+ hlen = mbedcrypto_md_get_size( md_ctx->md_info );
+
+ /* Generate and apply dbMask */
+ p = dst;
+
+ while( dlen > 0 )
+ {
+ use_len = hlen;
+ if( dlen < hlen )
+ use_len = dlen;
+
+ if( ( ret = mbedcrypto_md_starts( md_ctx ) ) != 0 )
+ goto exit;
+ if( ( ret = mbedcrypto_md_update( md_ctx, src, slen ) ) != 0 )
+ goto exit;
+ if( ( ret = mbedcrypto_md_update( md_ctx, counter, 4 ) ) != 0 )
+ goto exit;
+ if( ( ret = mbedcrypto_md_finish( md_ctx, mask ) ) != 0 )
+ goto exit;
+
+ for( i = 0; i < use_len; ++i )
+ *p++ ^= mask[i];
+
+ counter[3]++;
+
+ dlen -= use_len;
+ }
+
+exit:
+ mbedcrypto_platform_zeroize( mask, sizeof( mask ) );
+
+ return( ret );
+}
+#endif /* MBEDCRYPTO_PKCS1_V21 */
+
+#if defined(MBEDCRYPTO_PKCS1_V21)
+/*
+ * Implementation of the PKCS#1 v2.1 RSAES-OAEP-ENCRYPT function
+ */
+int mbedcrypto_rsa_rsaes_oaep_encrypt( mbedcrypto_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode,
+ const unsigned char *label, size_t label_len,
+ size_t ilen,
+ const unsigned char *input,
+ unsigned char *output )
+{
+ size_t olen;
+ int ret;
+ unsigned char *p = output;
+ unsigned int hlen;
+ const mbedcrypto_md_info_t *md_info;
+ mbedcrypto_md_context_t md_ctx;
+
+ if( mode == MBEDCRYPTO_RSA_PRIVATE && ctx->padding != MBEDCRYPTO_RSA_PKCS_V21 )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ if( f_rng == NULL )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ md_info = mbedcrypto_md_info_from_type( (mbedcrypto_md_type_t) ctx->hash_id );
+ if( md_info == NULL )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ olen = ctx->len;
+ hlen = mbedcrypto_md_get_size( md_info );
+
+ /* first comparison checks for overflow */
+ if( ilen + 2 * hlen + 2 < ilen || olen < ilen + 2 * hlen + 2 )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ memset( output, 0, olen );
+
+ *p++ = 0;
+
+ /* Generate a random octet string seed */
+ if( ( ret = f_rng( p_rng, p, hlen ) ) != 0 )
+ return( MBEDCRYPTO_ERR_RSA_RNG_FAILED + ret );
+
+ p += hlen;
+
+ /* Construct DB */
+ if( ( ret = mbedcrypto_md( md_info, label, label_len, p ) ) != 0 )
+ return( ret );
+ p += hlen;
+ p += olen - 2 * hlen - 2 - ilen;
+ *p++ = 1;
+ if( ilen != 0 )
+ memcpy( p, input, ilen );
+
+ mbedcrypto_md_init( &md_ctx );
+ if( ( ret = mbedcrypto_md_setup( &md_ctx, md_info, 0 ) ) != 0 )
+ goto exit;
+
+ /* maskedDB: Apply dbMask to DB */
+ if( ( ret = mgf_mask( output + hlen + 1, olen - hlen - 1, output + 1, hlen,
+ &md_ctx ) ) != 0 )
+ goto exit;
+
+ /* maskedSeed: Apply seedMask to seed */
+ if( ( ret = mgf_mask( output + 1, hlen, output + hlen + 1, olen - hlen - 1,
+ &md_ctx ) ) != 0 )
+ goto exit;
+
+exit:
+ mbedcrypto_md_free( &md_ctx );
+
+ if( ret != 0 )
+ return( ret );
+
+ return( ( mode == MBEDCRYPTO_RSA_PUBLIC )
+ ? mbedcrypto_rsa_public( ctx, output, output )
+ : mbedcrypto_rsa_private( ctx, f_rng, p_rng, output, output ) );
+}
+#endif /* MBEDCRYPTO_PKCS1_V21 */
+
+#if defined(MBEDCRYPTO_PKCS1_V15)
+/*
+ * Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-ENCRYPT function
+ */
+int mbedcrypto_rsa_rsaes_pkcs1_v15_encrypt( mbedcrypto_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode, size_t ilen,
+ const unsigned char *input,
+ unsigned char *output )
+{
+ size_t nb_pad, olen;
+ int ret;
+ unsigned char *p = output;
+
+ if( mode == MBEDCRYPTO_RSA_PRIVATE && ctx->padding != MBEDCRYPTO_RSA_PKCS_V15 )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ // We don't check p_rng because it won't be dereferenced here
+ if( f_rng == NULL || output == NULL )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+ if( ilen != 0 && input == NULL )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ olen = ctx->len;
+
+ /* first comparison checks for overflow */
+ if( ilen + 11 < ilen || olen < ilen + 11 )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ nb_pad = olen - 3 - ilen;
+
+ *p++ = 0;
+ if( mode == MBEDCRYPTO_RSA_PUBLIC )
+ {
+ *p++ = MBEDCRYPTO_RSA_CRYPT;
+
+ while( nb_pad-- > 0 )
+ {
+ int rng_dl = 100;
+
+ do {
+ ret = f_rng( p_rng, p, 1 );
+ } while( *p == 0 && --rng_dl && ret == 0 );
+
+ /* Check if RNG failed to generate data */
+ if( rng_dl == 0 || ret != 0 )
+ return( MBEDCRYPTO_ERR_RSA_RNG_FAILED + ret );
+
+ p++;
+ }
+ }
+ else
+ {
+ *p++ = MBEDCRYPTO_RSA_SIGN;
+
+ while( nb_pad-- > 0 )
+ *p++ = 0xFF;
+ }
+
+ *p++ = 0;
+ if( ilen != 0 )
+ memcpy( p, input, ilen );
+
+ return( ( mode == MBEDCRYPTO_RSA_PUBLIC )
+ ? mbedcrypto_rsa_public( ctx, output, output )
+ : mbedcrypto_rsa_private( ctx, f_rng, p_rng, output, output ) );
+}
+#endif /* MBEDCRYPTO_PKCS1_V15 */
+
+/*
+ * Add the message padding, then do an RSA operation
+ */
+int mbedcrypto_rsa_pkcs1_encrypt( mbedcrypto_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode, size_t ilen,
+ const unsigned char *input,
+ unsigned char *output )
+{
+ switch( ctx->padding )
+ {
+#if defined(MBEDCRYPTO_PKCS1_V15)
+ case MBEDCRYPTO_RSA_PKCS_V15:
+ return mbedcrypto_rsa_rsaes_pkcs1_v15_encrypt( ctx, f_rng, p_rng, mode, ilen,
+ input, output );
+#endif
+
+#if defined(MBEDCRYPTO_PKCS1_V21)
+ case MBEDCRYPTO_RSA_PKCS_V21:
+ return mbedcrypto_rsa_rsaes_oaep_encrypt( ctx, f_rng, p_rng, mode, NULL, 0,
+ ilen, input, output );
+#endif
+
+ default:
+ return( MBEDCRYPTO_ERR_RSA_INVALID_PADDING );
+ }
+}
+
+#if defined(MBEDCRYPTO_PKCS1_V21)
+/*
+ * Implementation of the PKCS#1 v2.1 RSAES-OAEP-DECRYPT function
+ */
+int mbedcrypto_rsa_rsaes_oaep_decrypt( mbedcrypto_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode,
+ const unsigned char *label, size_t label_len,
+ size_t *olen,
+ const unsigned char *input,
+ unsigned char *output,
+ size_t output_max_len )
+{
+ int ret;
+ size_t ilen, i, pad_len;
+ unsigned char *p, bad, pad_done;
+ unsigned char buf[MBEDCRYPTO_MPI_MAX_SIZE];
+ unsigned char lhash[MBEDCRYPTO_MD_MAX_SIZE];
+ unsigned int hlen;
+ const mbedcrypto_md_info_t *md_info;
+ mbedcrypto_md_context_t md_ctx;
+
+ /*
+ * Parameters sanity checks
+ */
+ if( mode == MBEDCRYPTO_RSA_PRIVATE && ctx->padding != MBEDCRYPTO_RSA_PKCS_V21 )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ ilen = ctx->len;
+
+ if( ilen < 16 || ilen > sizeof( buf ) )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ md_info = mbedcrypto_md_info_from_type( (mbedcrypto_md_type_t) ctx->hash_id );
+ if( md_info == NULL )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ hlen = mbedcrypto_md_get_size( md_info );
+
+ // checking for integer underflow
+ if( 2 * hlen + 2 > ilen )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ /*
+ * RSA operation
+ */
+ ret = ( mode == MBEDCRYPTO_RSA_PUBLIC )
+ ? mbedcrypto_rsa_public( ctx, input, buf )
+ : mbedcrypto_rsa_private( ctx, f_rng, p_rng, input, buf );
+
+ if( ret != 0 )
+ goto cleanup;
+
+ /*
+ * Unmask data and generate lHash
+ */
+ mbedcrypto_md_init( &md_ctx );
+ if( ( ret = mbedcrypto_md_setup( &md_ctx, md_info, 0 ) ) != 0 )
+ {
+ mbedcrypto_md_free( &md_ctx );
+ goto cleanup;
+ }
+
+ /* seed: Apply seedMask to maskedSeed */
+ if( ( ret = mgf_mask( buf + 1, hlen, buf + hlen + 1, ilen - hlen - 1,
+ &md_ctx ) ) != 0 ||
+ /* DB: Apply dbMask to maskedDB */
+ ( ret = mgf_mask( buf + hlen + 1, ilen - hlen - 1, buf + 1, hlen,
+ &md_ctx ) ) != 0 )
+ {
+ mbedcrypto_md_free( &md_ctx );
+ goto cleanup;
+ }
+
+ mbedcrypto_md_free( &md_ctx );
+
+ /* Generate lHash */
+ if( ( ret = mbedcrypto_md( md_info, label, label_len, lhash ) ) != 0 )
+ goto cleanup;
+
+ /*
+ * Check contents, in "constant-time"
+ */
+ p = buf;
+ bad = 0;
+
+ bad |= *p++; /* First byte must be 0 */
+
+ p += hlen; /* Skip seed */
+
+ /* Check lHash */
+ for( i = 0; i < hlen; i++ )
+ bad |= lhash[i] ^ *p++;
+
+ /* Get zero-padding len, but always read till end of buffer
+ * (minus one, for the 01 byte) */
+ pad_len = 0;
+ pad_done = 0;
+ for( i = 0; i < ilen - 2 * hlen - 2; i++ )
+ {
+ pad_done |= p[i];
+ pad_len += ((pad_done | (unsigned char)-pad_done) >> 7) ^ 1;
+ }
+
+ p += pad_len;
+ bad |= *p++ ^ 0x01;
+
+ /*
+ * The only information "leaked" is whether the padding was correct or not
+ * (eg, no data is copied if it was not correct). This meets the
+ * recommendations in PKCS#1 v2.2: an opponent cannot distinguish between
+ * the different error conditions.
+ */
+ if( bad != 0 )
+ {
+ ret = MBEDCRYPTO_ERR_RSA_INVALID_PADDING;
+ goto cleanup;
+ }
+
+ if( ilen - ( p - buf ) > output_max_len )
+ {
+ ret = MBEDCRYPTO_ERR_RSA_OUTPUT_TOO_LARGE;
+ goto cleanup;
+ }
+
+ *olen = ilen - (p - buf);
+ if( *olen != 0 )
+ memcpy( output, p, *olen );
+ ret = 0;
+
+cleanup:
+ mbedcrypto_platform_zeroize( buf, sizeof( buf ) );
+ mbedcrypto_platform_zeroize( lhash, sizeof( lhash ) );
+
+ return( ret );
+}
+#endif /* MBEDCRYPTO_PKCS1_V21 */
+
+#if defined(MBEDCRYPTO_PKCS1_V15)
+/*
+ * Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-DECRYPT function
+ */
+int mbedcrypto_rsa_rsaes_pkcs1_v15_decrypt( mbedcrypto_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode, size_t *olen,
+ const unsigned char *input,
+ unsigned char *output,
+ size_t output_max_len)
+{
+ int ret;
+ size_t ilen, pad_count = 0, i;
+ unsigned char *p, bad, pad_done = 0;
+ unsigned char buf[MBEDCRYPTO_MPI_MAX_SIZE];
+
+ if( mode == MBEDCRYPTO_RSA_PRIVATE && ctx->padding != MBEDCRYPTO_RSA_PKCS_V15 )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ ilen = ctx->len;
+
+ if( ilen < 16 || ilen > sizeof( buf ) )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ ret = ( mode == MBEDCRYPTO_RSA_PUBLIC )
+ ? mbedcrypto_rsa_public( ctx, input, buf )
+ : mbedcrypto_rsa_private( ctx, f_rng, p_rng, input, buf );
+
+ if( ret != 0 )
+ goto cleanup;
+
+ p = buf;
+ bad = 0;
+
+ /*
+ * Check and get padding len in "constant-time"
+ */
+ bad |= *p++; /* First byte must be 0 */
+
+ /* This test does not depend on secret data */
+ if( mode == MBEDCRYPTO_RSA_PRIVATE )
+ {
+ bad |= *p++ ^ MBEDCRYPTO_RSA_CRYPT;
+
+ /* Get padding len, but always read till end of buffer
+ * (minus one, for the 00 byte) */
+ for( i = 0; i < ilen - 3; i++ )
+ {
+ pad_done |= ((p[i] | (unsigned char)-p[i]) >> 7) ^ 1;
+ pad_count += ((pad_done | (unsigned char)-pad_done) >> 7) ^ 1;
+ }
+
+ p += pad_count;
+ bad |= *p++; /* Must be zero */
+ }
+ else
+ {
+ bad |= *p++ ^ MBEDCRYPTO_RSA_SIGN;
+
+ /* Get padding len, but always read till end of buffer
+ * (minus one, for the 00 byte) */
+ for( i = 0; i < ilen - 3; i++ )
+ {
+ pad_done |= ( p[i] != 0xFF );
+ pad_count += ( pad_done == 0 );
+ }
+
+ p += pad_count;
+ bad |= *p++; /* Must be zero */
+ }
+
+ bad |= ( pad_count < 8 );
+
+ if( bad )
+ {
+ ret = MBEDCRYPTO_ERR_RSA_INVALID_PADDING;
+ goto cleanup;
+ }
+
+ if( ilen - ( p - buf ) > output_max_len )
+ {
+ ret = MBEDCRYPTO_ERR_RSA_OUTPUT_TOO_LARGE;
+ goto cleanup;
+ }
+
+ *olen = ilen - (p - buf);
+ if( *olen != 0 )
+ memcpy( output, p, *olen );
+ ret = 0;
+
+cleanup:
+ mbedcrypto_platform_zeroize( buf, sizeof( buf ) );
+
+ return( ret );
+}
+#endif /* MBEDCRYPTO_PKCS1_V15 */
+
+/*
+ * Do an RSA operation, then remove the message padding
+ */
+int mbedcrypto_rsa_pkcs1_decrypt( mbedcrypto_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode, size_t *olen,
+ const unsigned char *input,
+ unsigned char *output,
+ size_t output_max_len)
+{
+ switch( ctx->padding )
+ {
+#if defined(MBEDCRYPTO_PKCS1_V15)
+ case MBEDCRYPTO_RSA_PKCS_V15:
+ return mbedcrypto_rsa_rsaes_pkcs1_v15_decrypt( ctx, f_rng, p_rng, mode, olen,
+ input, output, output_max_len );
+#endif
+
+#if defined(MBEDCRYPTO_PKCS1_V21)
+ case MBEDCRYPTO_RSA_PKCS_V21:
+ return mbedcrypto_rsa_rsaes_oaep_decrypt( ctx, f_rng, p_rng, mode, NULL, 0,
+ olen, input, output,
+ output_max_len );
+#endif
+
+ default:
+ return( MBEDCRYPTO_ERR_RSA_INVALID_PADDING );
+ }
+}
+
+#if defined(MBEDCRYPTO_PKCS1_V21)
+/*
+ * Implementation of the PKCS#1 v2.1 RSASSA-PSS-SIGN function
+ */
+int mbedcrypto_rsa_rsassa_pss_sign( mbedcrypto_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode,
+ mbedcrypto_md_type_t md_alg,
+ unsigned int hashlen,
+ const unsigned char *hash,
+ unsigned char *sig )
+{
+ size_t olen;
+ unsigned char *p = sig;
+ unsigned char salt[MBEDCRYPTO_MD_MAX_SIZE];
+ unsigned int slen, hlen, offset = 0;
+ int ret;
+ size_t msb;
+ const mbedcrypto_md_info_t *md_info;
+ mbedcrypto_md_context_t md_ctx;
+
+ if( mode == MBEDCRYPTO_RSA_PRIVATE && ctx->padding != MBEDCRYPTO_RSA_PKCS_V21 )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ if( f_rng == NULL )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ olen = ctx->len;
+
+ if( md_alg != MBEDCRYPTO_MD_NONE )
+ {
+ /* Gather length of hash to sign */
+ md_info = mbedcrypto_md_info_from_type( md_alg );
+ if( md_info == NULL )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ hashlen = mbedcrypto_md_get_size( md_info );
+ }
+
+ md_info = mbedcrypto_md_info_from_type( (mbedcrypto_md_type_t) ctx->hash_id );
+ if( md_info == NULL )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ hlen = mbedcrypto_md_get_size( md_info );
+ slen = hlen;
+
+ if( olen < hlen + slen + 2 )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ memset( sig, 0, olen );
+
+ /* Generate salt of length slen */
+ if( ( ret = f_rng( p_rng, salt, slen ) ) != 0 )
+ return( MBEDCRYPTO_ERR_RSA_RNG_FAILED + ret );
+
+ /* Note: EMSA-PSS encoding is over the length of N - 1 bits */
+ msb = mbedcrypto_mpi_bitlen( &ctx->N ) - 1;
+ p += olen - hlen * 2 - 2;
+ *p++ = 0x01;
+ memcpy( p, salt, slen );
+ p += slen;
+
+ mbedcrypto_md_init( &md_ctx );
+ if( ( ret = mbedcrypto_md_setup( &md_ctx, md_info, 0 ) ) != 0 )
+ goto exit;
+
+ /* Generate H = Hash( M' ) */
+ if( ( ret = mbedcrypto_md_starts( &md_ctx ) ) != 0 )
+ goto exit;
+ if( ( ret = mbedcrypto_md_update( &md_ctx, p, 8 ) ) != 0 )
+ goto exit;
+ if( ( ret = mbedcrypto_md_update( &md_ctx, hash, hashlen ) ) != 0 )
+ goto exit;
+ if( ( ret = mbedcrypto_md_update( &md_ctx, salt, slen ) ) != 0 )
+ goto exit;
+ if( ( ret = mbedcrypto_md_finish( &md_ctx, p ) ) != 0 )
+ goto exit;
+
+ /* Compensate for boundary condition when applying mask */
+ if( msb % 8 == 0 )
+ offset = 1;
+
+ /* maskedDB: Apply dbMask to DB */
+ if( ( ret = mgf_mask( sig + offset, olen - hlen - 1 - offset, p, hlen,
+ &md_ctx ) ) != 0 )
+ goto exit;
+
+ msb = mbedcrypto_mpi_bitlen( &ctx->N ) - 1;
+ sig[0] &= 0xFF >> ( olen * 8 - msb );
+
+ p += hlen;
+ *p++ = 0xBC;
+
+ mbedcrypto_platform_zeroize( salt, sizeof( salt ) );
+
+exit:
+ mbedcrypto_md_free( &md_ctx );
+
+ if( ret != 0 )
+ return( ret );
+
+ return( ( mode == MBEDCRYPTO_RSA_PUBLIC )
+ ? mbedcrypto_rsa_public( ctx, sig, sig )
+ : mbedcrypto_rsa_private( ctx, f_rng, p_rng, sig, sig ) );
+}
+#endif /* MBEDCRYPTO_PKCS1_V21 */
+
+#if defined(MBEDCRYPTO_PKCS1_V15)
+/*
+ * Implementation of the PKCS#1 v2.1 RSASSA-PKCS1-V1_5-SIGN function
+ */
+
+/* Construct a PKCS v1.5 encoding of a hashed message
+ *
+ * This is used both for signature generation and verification.
+ *
+ * Parameters:
+ * - md_alg: Identifies the hash algorithm used to generate the given hash;
+ * MBEDCRYPTO_MD_NONE if raw data is signed.
+ * - hashlen: Length of hash in case hashlen is MBEDCRYPTO_MD_NONE.
+ * - hash: Buffer containing the hashed message or the raw data.
+ * - dst_len: Length of the encoded message.
+ * - dst: Buffer to hold the encoded message.
+ *
+ * Assumptions:
+ * - hash has size hashlen if md_alg == MBEDCRYPTO_MD_NONE.
+ * - hash has size corresponding to md_alg if md_alg != MBEDCRYPTO_MD_NONE.
+ * - dst points to a buffer of size at least dst_len.
+ *
+ */
+static int rsa_rsassa_pkcs1_v15_encode( mbedcrypto_md_type_t md_alg,
+ unsigned int hashlen,
+ const unsigned char *hash,
+ size_t dst_len,
+ unsigned char *dst )
+{
+ size_t oid_size = 0;
+ size_t nb_pad = dst_len;
+ unsigned char *p = dst;
+ const char *oid = NULL;
+
+ /* Are we signing hashed or raw data? */
+ if( md_alg != MBEDCRYPTO_MD_NONE )
+ {
+ const mbedcrypto_md_info_t *md_info = mbedcrypto_md_info_from_type( md_alg );
+ if( md_info == NULL )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ if( mbedcrypto_oid_get_oid_by_md( md_alg, &oid, &oid_size ) != 0 )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ hashlen = mbedcrypto_md_get_size( md_info );
+
+ /* Double-check that 8 + hashlen + oid_size can be used as a
+ * 1-byte ASN.1 length encoding and that there's no overflow. */
+ if( 8 + hashlen + oid_size >= 0x80 ||
+ 10 + hashlen < hashlen ||
+ 10 + hashlen + oid_size < 10 + hashlen )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ /*
+ * Static bounds check:
+ * - Need 10 bytes for five tag-length pairs.
+ * (Insist on 1-byte length encodings to protect against variants of
+ * Bleichenbacher's forgery attack against lax PKCS#1v1.5 verification)
+ * - Need hashlen bytes for hash
+ * - Need oid_size bytes for hash alg OID.
+ */
+ if( nb_pad < 10 + hashlen + oid_size )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+ nb_pad -= 10 + hashlen + oid_size;
+ }
+ else
+ {
+ if( nb_pad < hashlen )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ nb_pad -= hashlen;
+ }
+
+ /* Need space for signature header and padding delimiter (3 bytes),
+ * and 8 bytes for the minimal padding */
+ if( nb_pad < 3 + 8 )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+ nb_pad -= 3;
+
+ /* Now nb_pad is the amount of memory to be filled
+ * with padding, and at least 8 bytes long. */
+
+ /* Write signature header and padding */
+ *p++ = 0;
+ *p++ = MBEDCRYPTO_RSA_SIGN;
+ memset( p, 0xFF, nb_pad );
+ p += nb_pad;
+ *p++ = 0;
+
+ /* Are we signing raw data? */
+ if( md_alg == MBEDCRYPTO_MD_NONE )
+ {
+ memcpy( p, hash, hashlen );
+ return( 0 );
+ }
+
+ /* Signing hashed data, add corresponding ASN.1 structure
+ *
+ * DigestInfo ::= SEQUENCE {
+ * digestAlgorithm DigestAlgorithmIdentifier,
+ * digest Digest }
+ * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+ * Digest ::= OCTET STRING
+ *
+ * Schematic:
+ * TAG-SEQ + LEN [ TAG-SEQ + LEN [ TAG-OID + LEN [ OID ]
+ * TAG-NULL + LEN [ NULL ] ]
+ * TAG-OCTET + LEN [ HASH ] ]
+ */
+ *p++ = MBEDCRYPTO_ASN1_SEQUENCE | MBEDCRYPTO_ASN1_CONSTRUCTED;
+ *p++ = (unsigned char)( 0x08 + oid_size + hashlen );
+ *p++ = MBEDCRYPTO_ASN1_SEQUENCE | MBEDCRYPTO_ASN1_CONSTRUCTED;
+ *p++ = (unsigned char)( 0x04 + oid_size );
+ *p++ = MBEDCRYPTO_ASN1_OID;
+ *p++ = (unsigned char) oid_size;
+ memcpy( p, oid, oid_size );
+ p += oid_size;
+ *p++ = MBEDCRYPTO_ASN1_NULL;
+ *p++ = 0x00;
+ *p++ = MBEDCRYPTO_ASN1_OCTET_STRING;
+ *p++ = (unsigned char) hashlen;
+ memcpy( p, hash, hashlen );
+ p += hashlen;
+
+ /* Just a sanity-check, should be automatic
+ * after the initial bounds check. */
+ if( p != dst + dst_len )
+ {
+ mbedcrypto_platform_zeroize( dst, dst_len );
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+ }
+
+ return( 0 );
+}
+
+/*
+ * Do an RSA operation to sign the message digest
+ */
+int mbedcrypto_rsa_rsassa_pkcs1_v15_sign( mbedcrypto_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode,
+ mbedcrypto_md_type_t md_alg,
+ unsigned int hashlen,
+ const unsigned char *hash,
+ unsigned char *sig )
+{
+ int ret;
+ unsigned char *sig_try = NULL, *verif = NULL;
+
+ if( mode == MBEDCRYPTO_RSA_PRIVATE && ctx->padding != MBEDCRYPTO_RSA_PKCS_V15 )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ /*
+ * Prepare PKCS1-v1.5 encoding (padding and hash identifier)
+ */
+
+ if( ( ret = rsa_rsassa_pkcs1_v15_encode( md_alg, hashlen, hash,
+ ctx->len, sig ) ) != 0 )
+ return( ret );
+
+ /*
+ * Call respective RSA primitive
+ */
+
+ if( mode == MBEDCRYPTO_RSA_PUBLIC )
+ {
+ /* Skip verification on a public key operation */
+ return( mbedcrypto_rsa_public( ctx, sig, sig ) );
+ }
+
+ /* Private key operation
+ *
+ * In order to prevent Lenstra's attack, make the signature in a
+ * temporary buffer and check it before returning it.
+ */
+
+ sig_try = mbedcrypto_calloc( 1, ctx->len );
+ if( sig_try == NULL )
+ return( MBEDCRYPTO_ERR_MPI_ALLOC_FAILED );
+
+ verif = mbedcrypto_calloc( 1, ctx->len );
+ if( verif == NULL )
+ {
+ mbedcrypto_free( sig_try );
+ return( MBEDCRYPTO_ERR_MPI_ALLOC_FAILED );
+ }
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_rsa_private( ctx, f_rng, p_rng, sig, sig_try ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_rsa_public( ctx, sig_try, verif ) );
+
+ if( mbedcrypto_safer_memcmp( verif, sig, ctx->len ) != 0 )
+ {
+ ret = MBEDCRYPTO_ERR_RSA_PRIVATE_FAILED;
+ goto cleanup;
+ }
+
+ memcpy( sig, sig_try, ctx->len );
+
+cleanup:
+ mbedcrypto_free( sig_try );
+ mbedcrypto_free( verif );
+
+ return( ret );
+}
+#endif /* MBEDCRYPTO_PKCS1_V15 */
+
+/*
+ * Do an RSA operation to sign the message digest
+ */
+int mbedcrypto_rsa_pkcs1_sign( mbedcrypto_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode,
+ mbedcrypto_md_type_t md_alg,
+ unsigned int hashlen,
+ const unsigned char *hash,
+ unsigned char *sig )
+{
+ switch( ctx->padding )
+ {
+#if defined(MBEDCRYPTO_PKCS1_V15)
+ case MBEDCRYPTO_RSA_PKCS_V15:
+ return mbedcrypto_rsa_rsassa_pkcs1_v15_sign( ctx, f_rng, p_rng, mode, md_alg,
+ hashlen, hash, sig );
+#endif
+
+#if defined(MBEDCRYPTO_PKCS1_V21)
+ case MBEDCRYPTO_RSA_PKCS_V21:
+ return mbedcrypto_rsa_rsassa_pss_sign( ctx, f_rng, p_rng, mode, md_alg,
+ hashlen, hash, sig );
+#endif
+
+ default:
+ return( MBEDCRYPTO_ERR_RSA_INVALID_PADDING );
+ }
+}
+
+#if defined(MBEDCRYPTO_PKCS1_V21)
+/*
+ * Implementation of the PKCS#1 v2.1 RSASSA-PSS-VERIFY function
+ */
+int mbedcrypto_rsa_rsassa_pss_verify_ext( mbedcrypto_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode,
+ mbedcrypto_md_type_t md_alg,
+ unsigned int hashlen,
+ const unsigned char *hash,
+ mbedcrypto_md_type_t mgf1_hash_id,
+ int expected_salt_len,
+ const unsigned char *sig )
+{
+ int ret;
+ size_t siglen;
+ unsigned char *p;
+ unsigned char *hash_start;
+ unsigned char result[MBEDCRYPTO_MD_MAX_SIZE];
+ unsigned char zeros[8];
+ unsigned int hlen;
+ size_t observed_salt_len, msb;
+ const mbedcrypto_md_info_t *md_info;
+ mbedcrypto_md_context_t md_ctx;
+ unsigned char buf[MBEDCRYPTO_MPI_MAX_SIZE];
+
+ if( mode == MBEDCRYPTO_RSA_PRIVATE && ctx->padding != MBEDCRYPTO_RSA_PKCS_V21 )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ siglen = ctx->len;
+
+ if( siglen < 16 || siglen > sizeof( buf ) )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ ret = ( mode == MBEDCRYPTO_RSA_PUBLIC )
+ ? mbedcrypto_rsa_public( ctx, sig, buf )
+ : mbedcrypto_rsa_private( ctx, f_rng, p_rng, sig, buf );
+
+ if( ret != 0 )
+ return( ret );
+
+ p = buf;
+
+ if( buf[siglen - 1] != 0xBC )
+ return( MBEDCRYPTO_ERR_RSA_INVALID_PADDING );
+
+ if( md_alg != MBEDCRYPTO_MD_NONE )
+ {
+ /* Gather length of hash to sign */
+ md_info = mbedcrypto_md_info_from_type( md_alg );
+ if( md_info == NULL )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ hashlen = mbedcrypto_md_get_size( md_info );
+ }
+
+ md_info = mbedcrypto_md_info_from_type( mgf1_hash_id );
+ if( md_info == NULL )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ hlen = mbedcrypto_md_get_size( md_info );
+
+ memset( zeros, 0, 8 );
+
+ /*
+ * Note: EMSA-PSS verification is over the length of N - 1 bits
+ */
+ msb = mbedcrypto_mpi_bitlen( &ctx->N ) - 1;
+
+ if( buf[0] >> ( 8 - siglen * 8 + msb ) )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ /* Compensate for boundary condition when applying mask */
+ if( msb % 8 == 0 )
+ {
+ p++;
+ siglen -= 1;
+ }
+
+ if( siglen < hlen + 2 )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+ hash_start = p + siglen - hlen - 1;
+
+ mbedcrypto_md_init( &md_ctx );
+ if( ( ret = mbedcrypto_md_setup( &md_ctx, md_info, 0 ) ) != 0 )
+ goto exit;
+
+ ret = mgf_mask( p, siglen - hlen - 1, hash_start, hlen, &md_ctx );
+ if( ret != 0 )
+ goto exit;
+
+ buf[0] &= 0xFF >> ( siglen * 8 - msb );
+
+ while( p < hash_start - 1 && *p == 0 )
+ p++;
+
+ if( *p++ != 0x01 )
+ {
+ ret = MBEDCRYPTO_ERR_RSA_INVALID_PADDING;
+ goto exit;
+ }
+
+ observed_salt_len = hash_start - p;
+
+ if( expected_salt_len != MBEDCRYPTO_RSA_SALT_LEN_ANY &&
+ observed_salt_len != (size_t) expected_salt_len )
+ {
+ ret = MBEDCRYPTO_ERR_RSA_INVALID_PADDING;
+ goto exit;
+ }
+
+ /*
+ * Generate H = Hash( M' )
+ */
+ ret = mbedcrypto_md_starts( &md_ctx );
+ if ( ret != 0 )
+ goto exit;
+ ret = mbedcrypto_md_update( &md_ctx, zeros, 8 );
+ if ( ret != 0 )
+ goto exit;
+ ret = mbedcrypto_md_update( &md_ctx, hash, hashlen );
+ if ( ret != 0 )
+ goto exit;
+ ret = mbedcrypto_md_update( &md_ctx, p, observed_salt_len );
+ if ( ret != 0 )
+ goto exit;
+ ret = mbedcrypto_md_finish( &md_ctx, result );
+ if ( ret != 0 )
+ goto exit;
+
+ if( memcmp( hash_start, result, hlen ) != 0 )
+ {
+ ret = MBEDCRYPTO_ERR_RSA_VERIFY_FAILED;
+ goto exit;
+ }
+
+exit:
+ mbedcrypto_md_free( &md_ctx );
+
+ return( ret );
+}
+
+/*
+ * Simplified PKCS#1 v2.1 RSASSA-PSS-VERIFY function
+ */
+int mbedcrypto_rsa_rsassa_pss_verify( mbedcrypto_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode,
+ mbedcrypto_md_type_t md_alg,
+ unsigned int hashlen,
+ const unsigned char *hash,
+ const unsigned char *sig )
+{
+ mbedcrypto_md_type_t mgf1_hash_id = ( ctx->hash_id != MBEDCRYPTO_MD_NONE )
+ ? (mbedcrypto_md_type_t) ctx->hash_id
+ : md_alg;
+
+ return( mbedcrypto_rsa_rsassa_pss_verify_ext( ctx, f_rng, p_rng, mode,
+ md_alg, hashlen, hash,
+ mgf1_hash_id, MBEDCRYPTO_RSA_SALT_LEN_ANY,
+ sig ) );
+
+}
+#endif /* MBEDCRYPTO_PKCS1_V21 */
+
+#if defined(MBEDCRYPTO_PKCS1_V15)
+/*
+ * Implementation of the PKCS#1 v2.1 RSASSA-PKCS1-v1_5-VERIFY function
+ */
+int mbedcrypto_rsa_rsassa_pkcs1_v15_verify( mbedcrypto_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode,
+ mbedcrypto_md_type_t md_alg,
+ unsigned int hashlen,
+ const unsigned char *hash,
+ const unsigned char *sig )
+{
+ int ret = 0;
+ const size_t sig_len = ctx->len;
+ unsigned char *encoded = NULL, *encoded_expected = NULL;
+
+ if( mode == MBEDCRYPTO_RSA_PRIVATE && ctx->padding != MBEDCRYPTO_RSA_PKCS_V15 )
+ return( MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA );
+
+ /*
+ * Prepare expected PKCS1 v1.5 encoding of hash.
+ */
+
+ if( ( encoded = mbedcrypto_calloc( 1, sig_len ) ) == NULL ||
+ ( encoded_expected = mbedcrypto_calloc( 1, sig_len ) ) == NULL )
+ {
+ ret = MBEDCRYPTO_ERR_MPI_ALLOC_FAILED;
+ goto cleanup;
+ }
+
+ if( ( ret = rsa_rsassa_pkcs1_v15_encode( md_alg, hashlen, hash, sig_len,
+ encoded_expected ) ) != 0 )
+ goto cleanup;
+
+ /*
+ * Apply RSA primitive to get what should be PKCS1 encoded hash.
+ */
+
+ ret = ( mode == MBEDCRYPTO_RSA_PUBLIC )
+ ? mbedcrypto_rsa_public( ctx, sig, encoded )
+ : mbedcrypto_rsa_private( ctx, f_rng, p_rng, sig, encoded );
+ if( ret != 0 )
+ goto cleanup;
+
+ /*
+ * Compare
+ */
+
+ if( ( ret = mbedcrypto_safer_memcmp( encoded, encoded_expected,
+ sig_len ) ) != 0 )
+ {
+ ret = MBEDCRYPTO_ERR_RSA_VERIFY_FAILED;
+ goto cleanup;
+ }
+
+cleanup:
+
+ if( encoded != NULL )
+ {
+ mbedcrypto_platform_zeroize( encoded, sig_len );
+ mbedcrypto_free( encoded );
+ }
+
+ if( encoded_expected != NULL )
+ {
+ mbedcrypto_platform_zeroize( encoded_expected, sig_len );
+ mbedcrypto_free( encoded_expected );
+ }
+
+ return( ret );
+}
+#endif /* MBEDCRYPTO_PKCS1_V15 */
+
+/*
+ * Do an RSA operation and check the message digest
+ */
+int mbedcrypto_rsa_pkcs1_verify( mbedcrypto_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode,
+ mbedcrypto_md_type_t md_alg,
+ unsigned int hashlen,
+ const unsigned char *hash,
+ const unsigned char *sig )
+{
+ switch( ctx->padding )
+ {
+#if defined(MBEDCRYPTO_PKCS1_V15)
+ case MBEDCRYPTO_RSA_PKCS_V15:
+ return mbedcrypto_rsa_rsassa_pkcs1_v15_verify( ctx, f_rng, p_rng, mode, md_alg,
+ hashlen, hash, sig );
+#endif
+
+#if defined(MBEDCRYPTO_PKCS1_V21)
+ case MBEDCRYPTO_RSA_PKCS_V21:
+ return mbedcrypto_rsa_rsassa_pss_verify( ctx, f_rng, p_rng, mode, md_alg,
+ hashlen, hash, sig );
+#endif
+
+ default:
+ return( MBEDCRYPTO_ERR_RSA_INVALID_PADDING );
+ }
+}
+
+/*
+ * Copy the components of an RSA key
+ */
+int mbedcrypto_rsa_copy( mbedcrypto_rsa_context *dst, const mbedcrypto_rsa_context *src )
+{
+ int ret;
+
+ dst->ver = src->ver;
+ dst->len = src->len;
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &dst->N, &src->N ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &dst->E, &src->E ) );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &dst->D, &src->D ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &dst->P, &src->P ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &dst->Q, &src->Q ) );
+
+#if !defined(MBEDCRYPTO_RSA_NO_CRT)
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &dst->DP, &src->DP ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &dst->DQ, &src->DQ ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &dst->QP, &src->QP ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &dst->RP, &src->RP ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &dst->RQ, &src->RQ ) );
+#endif
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &dst->RN, &src->RN ) );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &dst->Vi, &src->Vi ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_copy( &dst->Vf, &src->Vf ) );
+
+ dst->padding = src->padding;
+ dst->hash_id = src->hash_id;
+
+cleanup:
+ if( ret != 0 )
+ mbedcrypto_rsa_free( dst );
+
+ return( ret );
+}
+
+/*
+ * Free the components of an RSA key
+ */
+void mbedcrypto_rsa_free( mbedcrypto_rsa_context *ctx )
+{
+ mbedcrypto_mpi_free( &ctx->Vi ); mbedcrypto_mpi_free( &ctx->Vf );
+ mbedcrypto_mpi_free( &ctx->RN ); mbedcrypto_mpi_free( &ctx->D );
+ mbedcrypto_mpi_free( &ctx->Q ); mbedcrypto_mpi_free( &ctx->P );
+ mbedcrypto_mpi_free( &ctx->E ); mbedcrypto_mpi_free( &ctx->N );
+
+#if !defined(MBEDCRYPTO_RSA_NO_CRT)
+ mbedcrypto_mpi_free( &ctx->RQ ); mbedcrypto_mpi_free( &ctx->RP );
+ mbedcrypto_mpi_free( &ctx->QP ); mbedcrypto_mpi_free( &ctx->DQ );
+ mbedcrypto_mpi_free( &ctx->DP );
+#endif /* MBEDCRYPTO_RSA_NO_CRT */
+
+#if defined(MBEDCRYPTO_THREADING_C)
+ mbedcrypto_mutex_free( &ctx->mutex );
+#endif
+}
+
+#endif /* !MBEDCRYPTO_RSA_ALT */
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+
+#include "mbedcrypto/sha1.h"
+
+/*
+ * Example RSA-1024 keypair, for test purposes
+ */
+#define KEY_LEN 128
+
+#define RSA_N "9292758453063D803DD603D5E777D788" \
+ "8ED1D5BF35786190FA2F23EBC0848AEA" \
+ "DDA92CA6C3D80B32C4D109BE0F36D6AE" \
+ "7130B9CED7ACDF54CFC7555AC14EEBAB" \
+ "93A89813FBF3C4F8066D2D800F7C38A8" \
+ "1AE31942917403FF4946B0A83D3D3E05" \
+ "EE57C6F5F5606FB5D4BC6CD34EE0801A" \
+ "5E94BB77B07507233A0BC7BAC8F90F79"
+
+#define RSA_E "10001"
+
+#define RSA_D "24BF6185468786FDD303083D25E64EFC" \
+ "66CA472BC44D253102F8B4A9D3BFA750" \
+ "91386C0077937FE33FA3252D28855837" \
+ "AE1B484A8A9A45F7EE8C0C634F99E8CD" \
+ "DF79C5CE07EE72C7F123142198164234" \
+ "CABB724CF78B8173B9F880FC86322407" \
+ "AF1FEDFDDE2BEB674CA15F3E81A1521E" \
+ "071513A1E85B5DFA031F21ECAE91A34D"
+
+#define RSA_P "C36D0EB7FCD285223CFB5AABA5BDA3D8" \
+ "2C01CAD19EA484A87EA4377637E75500" \
+ "FCB2005C5C7DD6EC4AC023CDA285D796" \
+ "C3D9E75E1EFC42488BB4F1D13AC30A57"
+
+#define RSA_Q "C000DF51A7C77AE8D7C7370C1FF55B69" \
+ "E211C2B9E5DB1ED0BF61D0D9899620F4" \
+ "910E4168387E3C30AA1E00C339A79508" \
+ "8452DD96A9A5EA5D9DCA68DA636032AF"
+
+#define PT_LEN 24
+#define RSA_PT "\xAA\xBB\xCC\x03\x02\x01\x00\xFF\xFF\xFF\xFF\xFF" \
+ "\x11\x22\x33\x0A\x0B\x0C\xCC\xDD\xDD\xDD\xDD\xDD"
+
+#if defined(MBEDCRYPTO_PKCS1_V15)
+static int myrand( void *rng_state, unsigned char *output, size_t len )
+{
+#if !defined(__OpenBSD__)
+ size_t i;
+
+ if( rng_state != NULL )
+ rng_state = NULL;
+
+ for( i = 0; i < len; ++i )
+ output[i] = rand();
+#else
+ if( rng_state != NULL )
+ rng_state = NULL;
+
+ arc4random_buf( output, len );
+#endif /* !OpenBSD */
+
+ return( 0 );
+}
+#endif /* MBEDCRYPTO_PKCS1_V15 */
+
+/*
+ * Checkup routine
+ */
+int mbedcrypto_rsa_self_test( int verbose )
+{
+ int ret = 0;
+#if defined(MBEDCRYPTO_PKCS1_V15)
+ size_t len;
+ mbedcrypto_rsa_context rsa;
+ unsigned char rsa_plaintext[PT_LEN];
+ unsigned char rsa_decrypted[PT_LEN];
+ unsigned char rsa_ciphertext[KEY_LEN];
+#if defined(MBEDCRYPTO_SHA1_C)
+ unsigned char sha1sum[20];
+#endif
+
+ mbedcrypto_mpi K;
+
+ mbedcrypto_mpi_init( &K );
+ mbedcrypto_rsa_init( &rsa, MBEDCRYPTO_RSA_PKCS_V15, 0 );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_string( &K, 16, RSA_N ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_rsa_import( &rsa, &K, NULL, NULL, NULL, NULL ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_string( &K, 16, RSA_P ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_rsa_import( &rsa, NULL, &K, NULL, NULL, NULL ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_string( &K, 16, RSA_Q ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_rsa_import( &rsa, NULL, NULL, &K, NULL, NULL ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_string( &K, 16, RSA_D ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_rsa_import( &rsa, NULL, NULL, NULL, &K, NULL ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_read_string( &K, 16, RSA_E ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_rsa_import( &rsa, NULL, NULL, NULL, NULL, &K ) );
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_rsa_complete( &rsa ) );
+
+ if( verbose != 0 )
+ mbedcrypto_printf( " RSA key validation: " );
+
+ if( mbedcrypto_rsa_check_pubkey( &rsa ) != 0 ||
+ mbedcrypto_rsa_check_privkey( &rsa ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+
+ ret = 1;
+ goto cleanup;
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n PKCS#1 encryption : " );
+
+ memcpy( rsa_plaintext, RSA_PT, PT_LEN );
+
+ if( mbedcrypto_rsa_pkcs1_encrypt( &rsa, myrand, NULL, MBEDCRYPTO_RSA_PUBLIC,
+ PT_LEN, rsa_plaintext,
+ rsa_ciphertext ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+
+ ret = 1;
+ goto cleanup;
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n PKCS#1 decryption : " );
+
+ if( mbedcrypto_rsa_pkcs1_decrypt( &rsa, myrand, NULL, MBEDCRYPTO_RSA_PRIVATE,
+ &len, rsa_ciphertext, rsa_decrypted,
+ sizeof(rsa_decrypted) ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+
+ ret = 1;
+ goto cleanup;
+ }
+
+ if( memcmp( rsa_decrypted, rsa_plaintext, len ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+
+ ret = 1;
+ goto cleanup;
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+
+#if defined(MBEDCRYPTO_SHA1_C)
+ if( verbose != 0 )
+ mbedcrypto_printf( " PKCS#1 data sign : " );
+
+ if( mbedcrypto_sha1_ret( rsa_plaintext, PT_LEN, sha1sum ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+
+ return( 1 );
+ }
+
+ if( mbedcrypto_rsa_pkcs1_sign( &rsa, myrand, NULL,
+ MBEDCRYPTO_RSA_PRIVATE, MBEDCRYPTO_MD_SHA1, 0,
+ sha1sum, rsa_ciphertext ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+
+ ret = 1;
+ goto cleanup;
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n PKCS#1 sig. verify: " );
+
+ if( mbedcrypto_rsa_pkcs1_verify( &rsa, NULL, NULL,
+ MBEDCRYPTO_RSA_PUBLIC, MBEDCRYPTO_MD_SHA1, 0,
+ sha1sum, rsa_ciphertext ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+
+ ret = 1;
+ goto cleanup;
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+#endif /* MBEDCRYPTO_SHA1_C */
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "\n" );
+
+cleanup:
+ mbedcrypto_mpi_free( &K );
+ mbedcrypto_rsa_free( &rsa );
+#else /* MBEDCRYPTO_PKCS1_V15 */
+ ((void) verbose);
+#endif /* MBEDCRYPTO_PKCS1_V15 */
+ return( ret );
+}
+
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#endif /* MBEDCRYPTO_RSA_C */
diff --git a/library/rsa_internal.c b/library/rsa_internal.c
new file mode 100644
index 0000000..a46b7f4
--- /dev/null
+++ b/library/rsa_internal.c
@@ -0,0 +1,487 @@
+/*
+ * Helper functions for the RSA module
+ *
+ * Copyright (C) 2006-2017, 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 Crypto (https://tls.mbed.org)
+ *
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_RSA_C)
+
+#include "mbedcrypto/rsa.h"
+#include "mbedcrypto/bignum.h"
+#include "mbedcrypto/rsa_internal.h"
+
+/*
+ * Compute RSA prime factors from public and private exponents
+ *
+ * Summary of algorithm:
+ * Setting F := lcm(P-1,Q-1), the idea is as follows:
+ *
+ * (a) For any 1 <= X < N with gcd(X,N)=1, we have X^F = 1 modulo N, so X^(F/2)
+ * is a square root of 1 in Z/NZ. Since Z/NZ ~= Z/PZ x Z/QZ by CRT and the
+ * square roots of 1 in Z/PZ and Z/QZ are +1 and -1, this leaves the four
+ * possibilities X^(F/2) = (+-1, +-1). If it happens that X^(F/2) = (-1,+1)
+ * or (+1,-1), then gcd(X^(F/2) + 1, N) will be equal to one of the prime
+ * factors of N.
+ *
+ * (b) If we don't know F/2 but (F/2) * K for some odd (!) K, then the same
+ * construction still applies since (-)^K is the identity on the set of
+ * roots of 1 in Z/NZ.
+ *
+ * The public and private key primitives (-)^E and (-)^D are mutually inverse
+ * bijections on Z/NZ if and only if (-)^(DE) is the identity on Z/NZ, i.e.
+ * if and only if DE - 1 is a multiple of F, say DE - 1 = F * L.
+ * Splitting L = 2^t * K with K odd, we have
+ *
+ * DE - 1 = FL = (F/2) * (2^(t+1)) * K,
+ *
+ * so (F / 2) * K is among the numbers
+ *
+ * (DE - 1) >> 1, (DE - 1) >> 2, ..., (DE - 1) >> ord
+ *
+ * where ord is the order of 2 in (DE - 1).
+ * We can therefore iterate through these numbers apply the construction
+ * of (a) and (b) above to attempt to factor N.
+ *
+ */
+int mbedcrypto_rsa_deduce_primes( mbedcrypto_mpi const *N,
+ mbedcrypto_mpi const *E, mbedcrypto_mpi const *D,
+ mbedcrypto_mpi *P, mbedcrypto_mpi *Q )
+{
+ int ret = 0;
+
+ uint16_t attempt; /* Number of current attempt */
+ uint16_t iter; /* Number of squares computed in the current attempt */
+
+ uint16_t order; /* Order of 2 in DE - 1 */
+
+ mbedcrypto_mpi T; /* Holds largest odd divisor of DE - 1 */
+ mbedcrypto_mpi K; /* Temporary holding the current candidate */
+
+ const unsigned char primes[] = { 2,
+ 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
+ };
+
+ const size_t num_primes = sizeof( primes ) / sizeof( *primes );
+
+ if( P == NULL || Q == NULL || P->p != NULL || Q->p != NULL )
+ return( MBEDCRYPTO_ERR_MPI_BAD_INPUT_DATA );
+
+ if( mbedcrypto_mpi_cmp_int( N, 0 ) <= 0 ||
+ mbedcrypto_mpi_cmp_int( D, 1 ) <= 0 ||
+ mbedcrypto_mpi_cmp_mpi( D, N ) >= 0 ||
+ mbedcrypto_mpi_cmp_int( E, 1 ) <= 0 ||
+ mbedcrypto_mpi_cmp_mpi( E, N ) >= 0 )
+ {
+ return( MBEDCRYPTO_ERR_MPI_BAD_INPUT_DATA );
+ }
+
+ /*
+ * Initializations and temporary changes
+ */
+
+ mbedcrypto_mpi_init( &K );
+ mbedcrypto_mpi_init( &T );
+
+ /* T := DE - 1 */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &T, D, E ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_int( &T, &T, 1 ) );
+
+ if( ( order = (uint16_t) mbedcrypto_mpi_lsb( &T ) ) == 0 )
+ {
+ ret = MBEDCRYPTO_ERR_MPI_BAD_INPUT_DATA;
+ goto cleanup;
+ }
+
+ /* After this operation, T holds the largest odd divisor of DE - 1. */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_shift_r( &T, order ) );
+
+ /*
+ * Actual work
+ */
+
+ /* Skip trying 2 if N == 1 mod 8 */
+ attempt = 0;
+ if( N->p[0] % 8 == 1 )
+ attempt = 1;
+
+ for( ; attempt < num_primes; ++attempt )
+ {
+ mbedcrypto_mpi_lset( &K, primes[attempt] );
+
+ /* Check if gcd(K,N) = 1 */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_gcd( P, &K, N ) );
+ if( mbedcrypto_mpi_cmp_int( P, 1 ) != 0 )
+ continue;
+
+ /* Go through K^T + 1, K^(2T) + 1, K^(4T) + 1, ...
+ * and check whether they have nontrivial GCD with N. */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_exp_mod( &K, &K, &T, N,
+ Q /* temporarily use Q for storing Montgomery
+ * multiplication helper values */ ) );
+
+ for( iter = 1; iter <= order; ++iter )
+ {
+ /* If we reach 1 prematurely, there's no point
+ * in continuing to square K */
+ if( mbedcrypto_mpi_cmp_int( &K, 1 ) == 0 )
+ break;
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_add_int( &K, &K, 1 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_gcd( P, &K, N ) );
+
+ if( mbedcrypto_mpi_cmp_int( P, 1 ) == 1 &&
+ mbedcrypto_mpi_cmp_mpi( P, N ) == -1 )
+ {
+ /*
+ * Have found a nontrivial divisor P of N.
+ * Set Q := N / P.
+ */
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_div_mpi( Q, NULL, N, P ) );
+ goto cleanup;
+ }
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_int( &K, &K, 1 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &K, &K, &K ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mod_mpi( &K, &K, N ) );
+ }
+
+ /*
+ * If we get here, then either we prematurely aborted the loop because
+ * we reached 1, or K holds primes[attempt]^(DE - 1) mod N, which must
+ * be 1 if D,E,N were consistent.
+ * Check if that's the case and abort if not, to avoid very long,
+ * yet eventually failing, computations if N,D,E were not sane.
+ */
+ if( mbedcrypto_mpi_cmp_int( &K, 1 ) != 0 )
+ {
+ break;
+ }
+ }
+
+ ret = MBEDCRYPTO_ERR_MPI_BAD_INPUT_DATA;
+
+cleanup:
+
+ mbedcrypto_mpi_free( &K );
+ mbedcrypto_mpi_free( &T );
+ return( ret );
+}
+
+/*
+ * Given P, Q and the public exponent E, deduce D.
+ * This is essentially a modular inversion.
+ */
+int mbedcrypto_rsa_deduce_private_exponent( mbedcrypto_mpi const *P,
+ mbedcrypto_mpi const *Q,
+ mbedcrypto_mpi const *E,
+ mbedcrypto_mpi *D )
+{
+ int ret = 0;
+ mbedcrypto_mpi K, L;
+
+ if( D == NULL || mbedcrypto_mpi_cmp_int( D, 0 ) != 0 )
+ return( MBEDCRYPTO_ERR_MPI_BAD_INPUT_DATA );
+
+ if( mbedcrypto_mpi_cmp_int( P, 1 ) <= 0 ||
+ mbedcrypto_mpi_cmp_int( Q, 1 ) <= 0 ||
+ mbedcrypto_mpi_cmp_int( E, 0 ) == 0 )
+ {
+ return( MBEDCRYPTO_ERR_MPI_BAD_INPUT_DATA );
+ }
+
+ mbedcrypto_mpi_init( &K );
+ mbedcrypto_mpi_init( &L );
+
+ /* Temporarily put K := P-1 and L := Q-1 */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_int( &K, P, 1 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_int( &L, Q, 1 ) );
+
+ /* Temporarily put D := gcd(P-1, Q-1) */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_gcd( D, &K, &L ) );
+
+ /* K := LCM(P-1, Q-1) */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &K, &K, &L ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_div_mpi( &K, NULL, &K, D ) );
+
+ /* Compute modular inverse of E in LCM(P-1, Q-1) */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_inv_mod( D, E, &K ) );
+
+cleanup:
+
+ mbedcrypto_mpi_free( &K );
+ mbedcrypto_mpi_free( &L );
+
+ return( ret );
+}
+
+/*
+ * Check that RSA CRT parameters are in accordance with core parameters.
+ */
+int mbedcrypto_rsa_validate_crt( const mbedcrypto_mpi *P, const mbedcrypto_mpi *Q,
+ const mbedcrypto_mpi *D, const mbedcrypto_mpi *DP,
+ const mbedcrypto_mpi *DQ, const mbedcrypto_mpi *QP )
+{
+ int ret = 0;
+
+ mbedcrypto_mpi K, L;
+ mbedcrypto_mpi_init( &K );
+ mbedcrypto_mpi_init( &L );
+
+ /* Check that DP - D == 0 mod P - 1 */
+ if( DP != NULL )
+ {
+ if( P == NULL )
+ {
+ ret = MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA;
+ goto cleanup;
+ }
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_int( &K, P, 1 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &L, DP, D ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mod_mpi( &L, &L, &K ) );
+
+ if( mbedcrypto_mpi_cmp_int( &L, 0 ) != 0 )
+ {
+ ret = MBEDCRYPTO_ERR_RSA_KEY_CHECK_FAILED;
+ goto cleanup;
+ }
+ }
+
+ /* Check that DQ - D == 0 mod Q - 1 */
+ if( DQ != NULL )
+ {
+ if( Q == NULL )
+ {
+ ret = MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA;
+ goto cleanup;
+ }
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_int( &K, Q, 1 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_mpi( &L, DQ, D ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mod_mpi( &L, &L, &K ) );
+
+ if( mbedcrypto_mpi_cmp_int( &L, 0 ) != 0 )
+ {
+ ret = MBEDCRYPTO_ERR_RSA_KEY_CHECK_FAILED;
+ goto cleanup;
+ }
+ }
+
+ /* Check that QP * Q - 1 == 0 mod P */
+ if( QP != NULL )
+ {
+ if( P == NULL || Q == NULL )
+ {
+ ret = MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA;
+ goto cleanup;
+ }
+
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &K, QP, Q ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_int( &K, &K, 1 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mod_mpi( &K, &K, P ) );
+ if( mbedcrypto_mpi_cmp_int( &K, 0 ) != 0 )
+ {
+ ret = MBEDCRYPTO_ERR_RSA_KEY_CHECK_FAILED;
+ goto cleanup;
+ }
+ }
+
+cleanup:
+
+ /* Wrap MPI error codes by RSA check failure error code */
+ if( ret != 0 &&
+ ret != MBEDCRYPTO_ERR_RSA_KEY_CHECK_FAILED &&
+ ret != MBEDCRYPTO_ERR_RSA_BAD_INPUT_DATA )
+ {
+ ret += MBEDCRYPTO_ERR_RSA_KEY_CHECK_FAILED;
+ }
+
+ mbedcrypto_mpi_free( &K );
+ mbedcrypto_mpi_free( &L );
+
+ return( ret );
+}
+
+/*
+ * Check that core RSA parameters are sane.
+ */
+int mbedcrypto_rsa_validate_params( const mbedcrypto_mpi *N, const mbedcrypto_mpi *P,
+ const mbedcrypto_mpi *Q, const mbedcrypto_mpi *D,
+ const mbedcrypto_mpi *E,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng )
+{
+ int ret = 0;
+ mbedcrypto_mpi K, L;
+
+ mbedcrypto_mpi_init( &K );
+ mbedcrypto_mpi_init( &L );
+
+ /*
+ * Step 1: If PRNG provided, check that P and Q are prime
+ */
+
+#if defined(MBEDCRYPTO_GENPRIME)
+ if( f_rng != NULL && P != NULL &&
+ ( ret = mbedcrypto_mpi_is_prime( P, f_rng, p_rng ) ) != 0 )
+ {
+ ret = MBEDCRYPTO_ERR_RSA_KEY_CHECK_FAILED;
+ goto cleanup;
+ }
+
+ if( f_rng != NULL && Q != NULL &&
+ ( ret = mbedcrypto_mpi_is_prime( Q, f_rng, p_rng ) ) != 0 )
+ {
+ ret = MBEDCRYPTO_ERR_RSA_KEY_CHECK_FAILED;
+ goto cleanup;
+ }
+#else
+ ((void) f_rng);
+ ((void) p_rng);
+#endif /* MBEDCRYPTO_GENPRIME */
+
+ /*
+ * Step 2: Check that 1 < N = P * Q
+ */
+
+ if( P != NULL && Q != NULL && N != NULL )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &K, P, Q ) );
+ if( mbedcrypto_mpi_cmp_int( N, 1 ) <= 0 ||
+ mbedcrypto_mpi_cmp_mpi( &K, N ) != 0 )
+ {
+ ret = MBEDCRYPTO_ERR_RSA_KEY_CHECK_FAILED;
+ goto cleanup;
+ }
+ }
+
+ /*
+ * Step 3: Check and 1 < D, E < N if present.
+ */
+
+ if( N != NULL && D != NULL && E != NULL )
+ {
+ if ( mbedcrypto_mpi_cmp_int( D, 1 ) <= 0 ||
+ mbedcrypto_mpi_cmp_int( E, 1 ) <= 0 ||
+ mbedcrypto_mpi_cmp_mpi( D, N ) >= 0 ||
+ mbedcrypto_mpi_cmp_mpi( E, N ) >= 0 )
+ {
+ ret = MBEDCRYPTO_ERR_RSA_KEY_CHECK_FAILED;
+ goto cleanup;
+ }
+ }
+
+ /*
+ * Step 4: Check that D, E are inverse modulo P-1 and Q-1
+ */
+
+ if( P != NULL && Q != NULL && D != NULL && E != NULL )
+ {
+ if( mbedcrypto_mpi_cmp_int( P, 1 ) <= 0 ||
+ mbedcrypto_mpi_cmp_int( Q, 1 ) <= 0 )
+ {
+ ret = MBEDCRYPTO_ERR_RSA_KEY_CHECK_FAILED;
+ goto cleanup;
+ }
+
+ /* Compute DE-1 mod P-1 */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &K, D, E ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_int( &K, &K, 1 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_int( &L, P, 1 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mod_mpi( &K, &K, &L ) );
+ if( mbedcrypto_mpi_cmp_int( &K, 0 ) != 0 )
+ {
+ ret = MBEDCRYPTO_ERR_RSA_KEY_CHECK_FAILED;
+ goto cleanup;
+ }
+
+ /* Compute DE-1 mod Q-1 */
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mul_mpi( &K, D, E ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_int( &K, &K, 1 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_int( &L, Q, 1 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mod_mpi( &K, &K, &L ) );
+ if( mbedcrypto_mpi_cmp_int( &K, 0 ) != 0 )
+ {
+ ret = MBEDCRYPTO_ERR_RSA_KEY_CHECK_FAILED;
+ goto cleanup;
+ }
+ }
+
+cleanup:
+
+ mbedcrypto_mpi_free( &K );
+ mbedcrypto_mpi_free( &L );
+
+ /* Wrap MPI error codes by RSA check failure error code */
+ if( ret != 0 && ret != MBEDCRYPTO_ERR_RSA_KEY_CHECK_FAILED )
+ {
+ ret += MBEDCRYPTO_ERR_RSA_KEY_CHECK_FAILED;
+ }
+
+ return( ret );
+}
+
+int mbedcrypto_rsa_deduce_crt( const mbedcrypto_mpi *P, const mbedcrypto_mpi *Q,
+ const mbedcrypto_mpi *D, mbedcrypto_mpi *DP,
+ mbedcrypto_mpi *DQ, mbedcrypto_mpi *QP )
+{
+ int ret = 0;
+ mbedcrypto_mpi K;
+ mbedcrypto_mpi_init( &K );
+
+ /* DP = D mod P-1 */
+ if( DP != NULL )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_int( &K, P, 1 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mod_mpi( DP, D, &K ) );
+ }
+
+ /* DQ = D mod Q-1 */
+ if( DQ != NULL )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_sub_int( &K, Q, 1 ) );
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_mod_mpi( DQ, D, &K ) );
+ }
+
+ /* QP = Q^{-1} mod P */
+ if( QP != NULL )
+ {
+ MBEDCRYPTO_MPI_CHK( mbedcrypto_mpi_inv_mod( QP, Q, P ) );
+ }
+
+cleanup:
+ mbedcrypto_mpi_free( &K );
+
+ return( ret );
+}
+
+#endif /* MBEDCRYPTO_RSA_C */
diff --git a/library/sha1.c b/library/sha1.c
new file mode 100644
index 0000000..d0f3757
--- /dev/null
+++ b/library/sha1.c
@@ -0,0 +1,532 @@
+/*
+ * FIPS-180-1 compliant SHA-1 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 Crypto (https://tls.mbed.org)
+ */
+/*
+ * The SHA-1 standard was published by NIST in 1993.
+ *
+ * http://www.itl.nist.gov/fipspubs/fip180-1.htm
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_SHA1_C)
+
+#include "mbedcrypto/sha1.h"
+#include "mbedcrypto/platform_util.h"
+
+#include <string.h>
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#include <stdio.h>
+#define mbedcrypto_printf printf
+#endif /* MBEDCRYPTO_PLATFORM_C */
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#if !defined(MBEDCRYPTO_SHA1_ALT)
+
+/*
+ * 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
+
+void mbedcrypto_sha1_init( mbedcrypto_sha1_context *ctx )
+{
+ memset( ctx, 0, sizeof( mbedcrypto_sha1_context ) );
+}
+
+void mbedcrypto_sha1_free( mbedcrypto_sha1_context *ctx )
+{
+ if( ctx == NULL )
+ return;
+
+ mbedcrypto_platform_zeroize( ctx, sizeof( mbedcrypto_sha1_context ) );
+}
+
+void mbedcrypto_sha1_clone( mbedcrypto_sha1_context *dst,
+ const mbedcrypto_sha1_context *src )
+{
+ *dst = *src;
+}
+
+/*
+ * SHA-1 context setup
+ */
+int mbedcrypto_sha1_starts_ret( mbedcrypto_sha1_context *ctx )
+{
+ ctx->total[0] = 0;
+ ctx->total[1] = 0;
+
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xEFCDAB89;
+ ctx->state[2] = 0x98BADCFE;
+ ctx->state[3] = 0x10325476;
+ ctx->state[4] = 0xC3D2E1F0;
+
+ return( 0 );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_sha1_starts( mbedcrypto_sha1_context *ctx )
+{
+ mbedcrypto_sha1_starts_ret( ctx );
+}
+#endif
+
+#if !defined(MBEDCRYPTO_SHA1_PROCESS_ALT)
+int mbedcrypto_internal_sha1_process( mbedcrypto_sha1_context *ctx,
+ const unsigned char data[64] )
+{
+ uint32_t temp, W[16], A, B, C, D, E;
+
+ GET_UINT32_BE( W[ 0], data, 0 );
+ GET_UINT32_BE( W[ 1], data, 4 );
+ GET_UINT32_BE( W[ 2], data, 8 );
+ GET_UINT32_BE( W[ 3], data, 12 );
+ GET_UINT32_BE( W[ 4], data, 16 );
+ GET_UINT32_BE( W[ 5], data, 20 );
+ GET_UINT32_BE( W[ 6], data, 24 );
+ GET_UINT32_BE( W[ 7], data, 28 );
+ GET_UINT32_BE( W[ 8], data, 32 );
+ GET_UINT32_BE( W[ 9], data, 36 );
+ GET_UINT32_BE( W[10], data, 40 );
+ GET_UINT32_BE( W[11], data, 44 );
+ GET_UINT32_BE( W[12], data, 48 );
+ GET_UINT32_BE( W[13], data, 52 );
+ GET_UINT32_BE( W[14], data, 56 );
+ GET_UINT32_BE( W[15], data, 60 );
+
+#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
+
+#define R(t) \
+( \
+ temp = W[( t - 3 ) & 0x0F] ^ W[( t - 8 ) & 0x0F] ^ \
+ W[( t - 14 ) & 0x0F] ^ W[ t & 0x0F], \
+ ( W[t & 0x0F] = S(temp,1) ) \
+)
+
+#define P(a,b,c,d,e,x) \
+{ \
+ e += S(a,5) + F(b,c,d) + K + x; b = S(b,30); \
+}
+
+ A = ctx->state[0];
+ B = ctx->state[1];
+ C = ctx->state[2];
+ D = ctx->state[3];
+ E = ctx->state[4];
+
+#define F(x,y,z) (z ^ (x & (y ^ z)))
+#define K 0x5A827999
+
+ P( A, B, C, D, E, W[0] );
+ P( E, A, B, C, D, W[1] );
+ P( D, E, A, B, C, W[2] );
+ P( C, D, E, A, B, W[3] );
+ P( B, C, D, E, A, W[4] );
+ P( A, B, C, D, E, W[5] );
+ P( E, A, B, C, D, W[6] );
+ P( D, E, A, B, C, W[7] );
+ P( C, D, E, A, B, W[8] );
+ P( B, C, D, E, A, W[9] );
+ P( A, B, C, D, E, W[10] );
+ P( E, A, B, C, D, W[11] );
+ P( D, E, A, B, C, W[12] );
+ P( C, D, E, A, B, W[13] );
+ P( B, C, D, E, A, W[14] );
+ P( A, B, C, D, E, W[15] );
+ P( E, A, B, C, D, R(16) );
+ P( D, E, A, B, C, R(17) );
+ P( C, D, E, A, B, R(18) );
+ P( B, C, D, E, A, R(19) );
+
+#undef K
+#undef F
+
+#define F(x,y,z) (x ^ y ^ z)
+#define K 0x6ED9EBA1
+
+ P( A, B, C, D, E, R(20) );
+ P( E, A, B, C, D, R(21) );
+ P( D, E, A, B, C, R(22) );
+ P( C, D, E, A, B, R(23) );
+ P( B, C, D, E, A, R(24) );
+ P( A, B, C, D, E, R(25) );
+ P( E, A, B, C, D, R(26) );
+ P( D, E, A, B, C, R(27) );
+ P( C, D, E, A, B, R(28) );
+ P( B, C, D, E, A, R(29) );
+ P( A, B, C, D, E, R(30) );
+ P( E, A, B, C, D, R(31) );
+ P( D, E, A, B, C, R(32) );
+ P( C, D, E, A, B, R(33) );
+ P( B, C, D, E, A, R(34) );
+ P( A, B, C, D, E, R(35) );
+ P( E, A, B, C, D, R(36) );
+ P( D, E, A, B, C, R(37) );
+ P( C, D, E, A, B, R(38) );
+ P( B, C, D, E, A, R(39) );
+
+#undef K
+#undef F
+
+#define F(x,y,z) ((x & y) | (z & (x | y)))
+#define K 0x8F1BBCDC
+
+ P( A, B, C, D, E, R(40) );
+ P( E, A, B, C, D, R(41) );
+ P( D, E, A, B, C, R(42) );
+ P( C, D, E, A, B, R(43) );
+ P( B, C, D, E, A, R(44) );
+ P( A, B, C, D, E, R(45) );
+ P( E, A, B, C, D, R(46) );
+ P( D, E, A, B, C, R(47) );
+ P( C, D, E, A, B, R(48) );
+ P( B, C, D, E, A, R(49) );
+ P( A, B, C, D, E, R(50) );
+ P( E, A, B, C, D, R(51) );
+ P( D, E, A, B, C, R(52) );
+ P( C, D, E, A, B, R(53) );
+ P( B, C, D, E, A, R(54) );
+ P( A, B, C, D, E, R(55) );
+ P( E, A, B, C, D, R(56) );
+ P( D, E, A, B, C, R(57) );
+ P( C, D, E, A, B, R(58) );
+ P( B, C, D, E, A, R(59) );
+
+#undef K
+#undef F
+
+#define F(x,y,z) (x ^ y ^ z)
+#define K 0xCA62C1D6
+
+ P( A, B, C, D, E, R(60) );
+ P( E, A, B, C, D, R(61) );
+ P( D, E, A, B, C, R(62) );
+ P( C, D, E, A, B, R(63) );
+ P( B, C, D, E, A, R(64) );
+ P( A, B, C, D, E, R(65) );
+ P( E, A, B, C, D, R(66) );
+ P( D, E, A, B, C, R(67) );
+ P( C, D, E, A, B, R(68) );
+ P( B, C, D, E, A, R(69) );
+ P( A, B, C, D, E, R(70) );
+ P( E, A, B, C, D, R(71) );
+ P( D, E, A, B, C, R(72) );
+ P( C, D, E, A, B, R(73) );
+ P( B, C, D, E, A, R(74) );
+ P( A, B, C, D, E, R(75) );
+ P( E, A, B, C, D, R(76) );
+ P( D, E, A, B, C, R(77) );
+ P( C, D, E, A, B, R(78) );
+ P( B, C, D, E, A, R(79) );
+
+#undef K
+#undef F
+
+ ctx->state[0] += A;
+ ctx->state[1] += B;
+ ctx->state[2] += C;
+ ctx->state[3] += D;
+ ctx->state[4] += E;
+
+ return( 0 );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_sha1_process( mbedcrypto_sha1_context *ctx,
+ const unsigned char data[64] )
+{
+ mbedcrypto_internal_sha1_process( ctx, data );
+}
+#endif
+#endif /* !MBEDCRYPTO_SHA1_PROCESS_ALT */
+
+/*
+ * SHA-1 process buffer
+ */
+int mbedcrypto_sha1_update_ret( mbedcrypto_sha1_context *ctx,
+ const unsigned char *input,
+ size_t ilen )
+{
+ int ret;
+ size_t fill;
+ uint32_t left;
+
+ if( ilen == 0 )
+ return( 0 );
+
+ left = ctx->total[0] & 0x3F;
+ fill = 64 - left;
+
+ ctx->total[0] += (uint32_t) ilen;
+ ctx->total[0] &= 0xFFFFFFFF;
+
+ if( ctx->total[0] < (uint32_t) ilen )
+ ctx->total[1]++;
+
+ if( left && ilen >= fill )
+ {
+ memcpy( (void *) (ctx->buffer + left), input, fill );
+
+ if( ( ret = mbedcrypto_internal_sha1_process( ctx, ctx->buffer ) ) != 0 )
+ return( ret );
+
+ input += fill;
+ ilen -= fill;
+ left = 0;
+ }
+
+ while( ilen >= 64 )
+ {
+ if( ( ret = mbedcrypto_internal_sha1_process( ctx, input ) ) != 0 )
+ return( ret );
+
+ input += 64;
+ ilen -= 64;
+ }
+
+ if( ilen > 0 )
+ memcpy( (void *) (ctx->buffer + left), input, ilen );
+
+ return( 0 );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_sha1_update( mbedcrypto_sha1_context *ctx,
+ const unsigned char *input,
+ size_t ilen )
+{
+ mbedcrypto_sha1_update_ret( ctx, input, ilen );
+}
+#endif
+
+static const unsigned char sha1_padding[64] =
+{
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * SHA-1 final digest
+ */
+int mbedcrypto_sha1_finish_ret( mbedcrypto_sha1_context *ctx,
+ unsigned char output[20] )
+{
+ int ret;
+ uint32_t last, padn;
+ uint32_t high, low;
+ unsigned char msglen[8];
+
+ high = ( ctx->total[0] >> 29 )
+ | ( ctx->total[1] << 3 );
+ low = ( ctx->total[0] << 3 );
+
+ PUT_UINT32_BE( high, msglen, 0 );
+ PUT_UINT32_BE( low, msglen, 4 );
+
+ last = ctx->total[0] & 0x3F;
+ padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
+
+ if( ( ret = mbedcrypto_sha1_update_ret( ctx, sha1_padding, padn ) ) != 0 )
+ return( ret );
+ if( ( ret = mbedcrypto_sha1_update_ret( ctx, msglen, 8 ) ) != 0 )
+ return( ret );
+
+ PUT_UINT32_BE( ctx->state[0], output, 0 );
+ PUT_UINT32_BE( ctx->state[1], output, 4 );
+ PUT_UINT32_BE( ctx->state[2], output, 8 );
+ PUT_UINT32_BE( ctx->state[3], output, 12 );
+ PUT_UINT32_BE( ctx->state[4], output, 16 );
+
+ return( 0 );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_sha1_finish( mbedcrypto_sha1_context *ctx,
+ unsigned char output[20] )
+{
+ mbedcrypto_sha1_finish_ret( ctx, output );
+}
+#endif
+
+#endif /* !MBEDCRYPTO_SHA1_ALT */
+
+/*
+ * output = SHA-1( input buffer )
+ */
+int mbedcrypto_sha1_ret( const unsigned char *input,
+ size_t ilen,
+ unsigned char output[20] )
+{
+ int ret;
+ mbedcrypto_sha1_context ctx;
+
+ mbedcrypto_sha1_init( &ctx );
+
+ if( ( ret = mbedcrypto_sha1_starts_ret( &ctx ) ) != 0 )
+ goto exit;
+
+ if( ( ret = mbedcrypto_sha1_update_ret( &ctx, input, ilen ) ) != 0 )
+ goto exit;
+
+ if( ( ret = mbedcrypto_sha1_finish_ret( &ctx, output ) ) != 0 )
+ goto exit;
+
+exit:
+ mbedcrypto_sha1_free( &ctx );
+
+ return( ret );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_sha1( const unsigned char *input,
+ size_t ilen,
+ unsigned char output[20] )
+{
+ mbedcrypto_sha1_ret( input, ilen, output );
+}
+#endif
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+/*
+ * FIPS-180-1 test vectors
+ */
+static const unsigned char sha1_test_buf[3][57] =
+{
+ { "abc" },
+ { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" },
+ { "" }
+};
+
+static const size_t sha1_test_buflen[3] =
+{
+ 3, 56, 1000
+};
+
+static const unsigned char sha1_test_sum[3][20] =
+{
+ { 0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, 0xBA, 0x3E,
+ 0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C, 0x9C, 0xD0, 0xD8, 0x9D },
+ { 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E, 0xBA, 0xAE,
+ 0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5, 0xE5, 0x46, 0x70, 0xF1 },
+ { 0x34, 0xAA, 0x97, 0x3C, 0xD4, 0xC4, 0xDA, 0xA4, 0xF6, 0x1E,
+ 0xEB, 0x2B, 0xDB, 0xAD, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6F }
+};
+
+/*
+ * Checkup routine
+ */
+int mbedcrypto_sha1_self_test( int verbose )
+{
+ int i, j, buflen, ret = 0;
+ unsigned char buf[1024];
+ unsigned char sha1sum[20];
+ mbedcrypto_sha1_context ctx;
+
+ mbedcrypto_sha1_init( &ctx );
+
+ /*
+ * SHA-1
+ */
+ for( i = 0; i < 3; i++ )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( " SHA-1 test #%d: ", i + 1 );
+
+ if( ( ret = mbedcrypto_sha1_starts_ret( &ctx ) ) != 0 )
+ goto fail;
+
+ if( i == 2 )
+ {
+ memset( buf, 'a', buflen = 1000 );
+
+ for( j = 0; j < 1000; j++ )
+ {
+ ret = mbedcrypto_sha1_update_ret( &ctx, buf, buflen );
+ if( ret != 0 )
+ goto fail;
+ }
+ }
+ else
+ {
+ ret = mbedcrypto_sha1_update_ret( &ctx, sha1_test_buf[i],
+ sha1_test_buflen[i] );
+ if( ret != 0 )
+ goto fail;
+ }
+
+ if( ( ret = mbedcrypto_sha1_finish_ret( &ctx, sha1sum ) ) != 0 )
+ goto fail;
+
+ if( memcmp( sha1sum, sha1_test_sum[i], 20 ) != 0 )
+ {
+ ret = 1;
+ goto fail;
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "\n" );
+
+ goto exit;
+
+fail:
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+
+exit:
+ mbedcrypto_sha1_free( &ctx );
+
+ return( ret );
+}
+
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#endif /* MBEDCRYPTO_SHA1_C */
diff --git a/library/sha256.c b/library/sha256.c
new file mode 100644
index 0000000..d04a424
--- /dev/null
+++ b/library/sha256.c
@@ -0,0 +1,546 @@
+/*
+ * FIPS-180-2 compliant SHA-256 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 Crypto (https://tls.mbed.org)
+ */
+/*
+ * The SHA-256 Secure Hash Standard was published by NIST in 2002.
+ *
+ * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_SHA256_C)
+
+#include "mbedcrypto/sha256.h"
+#include "mbedcrypto/platform_util.h"
+
+#include <string.h>
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#define mbedcrypto_printf printf
+#define mbedcrypto_calloc calloc
+#define mbedcrypto_free free
+#endif /* MBEDCRYPTO_PLATFORM_C */
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#if !defined(MBEDCRYPTO_SHA256_ALT)
+
+/*
+ * 32-bit integer manipulation macros (big endian)
+ */
+#ifndef GET_UINT32_BE
+#define GET_UINT32_BE(n,b,i) \
+do { \
+ (n) = ( (uint32_t) (b)[(i) ] << 24 ) \
+ | ( (uint32_t) (b)[(i) + 1] << 16 ) \
+ | ( (uint32_t) (b)[(i) + 2] << 8 ) \
+ | ( (uint32_t) (b)[(i) + 3] ); \
+} while( 0 )
+#endif
+
+#ifndef PUT_UINT32_BE
+#define PUT_UINT32_BE(n,b,i) \
+do { \
+ (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) ); \
+} while( 0 )
+#endif
+
+void mbedcrypto_sha256_init( mbedcrypto_sha256_context *ctx )
+{
+ memset( ctx, 0, sizeof( mbedcrypto_sha256_context ) );
+}
+
+void mbedcrypto_sha256_free( mbedcrypto_sha256_context *ctx )
+{
+ if( ctx == NULL )
+ return;
+
+ mbedcrypto_platform_zeroize( ctx, sizeof( mbedcrypto_sha256_context ) );
+}
+
+void mbedcrypto_sha256_clone( mbedcrypto_sha256_context *dst,
+ const mbedcrypto_sha256_context *src )
+{
+ *dst = *src;
+}
+
+/*
+ * SHA-256 context setup
+ */
+int mbedcrypto_sha256_starts_ret( mbedcrypto_sha256_context *ctx, int is224 )
+{
+ ctx->total[0] = 0;
+ ctx->total[1] = 0;
+
+ if( is224 == 0 )
+ {
+ /* SHA-256 */
+ ctx->state[0] = 0x6A09E667;
+ ctx->state[1] = 0xBB67AE85;
+ ctx->state[2] = 0x3C6EF372;
+ ctx->state[3] = 0xA54FF53A;
+ ctx->state[4] = 0x510E527F;
+ ctx->state[5] = 0x9B05688C;
+ ctx->state[6] = 0x1F83D9AB;
+ ctx->state[7] = 0x5BE0CD19;
+ }
+ else
+ {
+ /* SHA-224 */
+ ctx->state[0] = 0xC1059ED8;
+ ctx->state[1] = 0x367CD507;
+ ctx->state[2] = 0x3070DD17;
+ ctx->state[3] = 0xF70E5939;
+ ctx->state[4] = 0xFFC00B31;
+ ctx->state[5] = 0x68581511;
+ ctx->state[6] = 0x64F98FA7;
+ ctx->state[7] = 0xBEFA4FA4;
+ }
+
+ ctx->is224 = is224;
+
+ return( 0 );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_sha256_starts( mbedcrypto_sha256_context *ctx,
+ int is224 )
+{
+ mbedcrypto_sha256_starts_ret( ctx, is224 );
+}
+#endif
+
+#if !defined(MBEDCRYPTO_SHA256_PROCESS_ALT)
+static const uint32_t K[] =
+{
+ 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
+ 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
+ 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
+ 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
+ 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
+ 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
+ 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
+ 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
+ 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
+ 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
+ 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
+ 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
+ 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
+ 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
+ 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
+ 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2,
+};
+
+#define SHR(x,n) ((x & 0xFFFFFFFF) >> n)
+#define ROTR(x,n) (SHR(x,n) | (x << (32 - n)))
+
+#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3))
+#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10))
+
+#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22))
+#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25))
+
+#define F0(x,y,z) ((x & y) | (z & (x | y)))
+#define F1(x,y,z) (z ^ (x & (y ^ z)))
+
+#define R(t) \
+( \
+ W[t] = S1(W[t - 2]) + W[t - 7] + \
+ S0(W[t - 15]) + W[t - 16] \
+)
+
+#define P(a,b,c,d,e,f,g,h,x,K) \
+{ \
+ temp1 = h + S3(e) + F1(e,f,g) + K + x; \
+ temp2 = S2(a) + F0(a,b,c); \
+ d += temp1; h = temp1 + temp2; \
+}
+
+int mbedcrypto_internal_sha256_process( mbedcrypto_sha256_context *ctx,
+ const unsigned char data[64] )
+{
+ uint32_t temp1, temp2, W[64];
+ uint32_t A[8];
+ unsigned int i;
+
+ for( i = 0; i < 8; i++ )
+ A[i] = ctx->state[i];
+
+#if defined(MBEDCRYPTO_SHA256_SMALLER)
+ for( i = 0; i < 64; i++ )
+ {
+ if( i < 16 )
+ GET_UINT32_BE( W[i], data, 4 * i );
+ else
+ R( i );
+
+ P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i], K[i] );
+
+ temp1 = A[7]; A[7] = A[6]; A[6] = A[5]; A[5] = A[4]; A[4] = A[3];
+ A[3] = A[2]; A[2] = A[1]; A[1] = A[0]; A[0] = temp1;
+ }
+#else /* MBEDCRYPTO_SHA256_SMALLER */
+ for( i = 0; i < 16; i++ )
+ GET_UINT32_BE( W[i], data, 4 * i );
+
+ for( i = 0; i < 16; i += 8 )
+ {
+ P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i+0], K[i+0] );
+ P( A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[i+1], K[i+1] );
+ P( A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[i+2], K[i+2] );
+ P( A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[i+3], K[i+3] );
+ P( A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[i+4], K[i+4] );
+ P( A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[i+5], K[i+5] );
+ P( A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[i+6], K[i+6] );
+ P( A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[i+7], K[i+7] );
+ }
+
+ for( i = 16; i < 64; i += 8 )
+ {
+ P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(i+0), K[i+0] );
+ P( A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(i+1), K[i+1] );
+ P( A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(i+2), K[i+2] );
+ P( A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(i+3), K[i+3] );
+ P( A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(i+4), K[i+4] );
+ P( A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(i+5), K[i+5] );
+ P( A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(i+6), K[i+6] );
+ P( A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(i+7), K[i+7] );
+ }
+#endif /* MBEDCRYPTO_SHA256_SMALLER */
+
+ for( i = 0; i < 8; i++ )
+ ctx->state[i] += A[i];
+
+ return( 0 );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_sha256_process( mbedcrypto_sha256_context *ctx,
+ const unsigned char data[64] )
+{
+ mbedcrypto_internal_sha256_process( ctx, data );
+}
+#endif
+#endif /* !MBEDCRYPTO_SHA256_PROCESS_ALT */
+
+/*
+ * SHA-256 process buffer
+ */
+int mbedcrypto_sha256_update_ret( mbedcrypto_sha256_context *ctx,
+ const unsigned char *input,
+ size_t ilen )
+{
+ int ret;
+ size_t fill;
+ uint32_t left;
+
+ if( ilen == 0 )
+ return( 0 );
+
+ left = ctx->total[0] & 0x3F;
+ fill = 64 - left;
+
+ ctx->total[0] += (uint32_t) ilen;
+ ctx->total[0] &= 0xFFFFFFFF;
+
+ if( ctx->total[0] < (uint32_t) ilen )
+ ctx->total[1]++;
+
+ if( left && ilen >= fill )
+ {
+ memcpy( (void *) (ctx->buffer + left), input, fill );
+
+ if( ( ret = mbedcrypto_internal_sha256_process( ctx, ctx->buffer ) ) != 0 )
+ return( ret );
+
+ input += fill;
+ ilen -= fill;
+ left = 0;
+ }
+
+ while( ilen >= 64 )
+ {
+ if( ( ret = mbedcrypto_internal_sha256_process( ctx, input ) ) != 0 )
+ return( ret );
+
+ input += 64;
+ ilen -= 64;
+ }
+
+ if( ilen > 0 )
+ memcpy( (void *) (ctx->buffer + left), input, ilen );
+
+ return( 0 );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_sha256_update( mbedcrypto_sha256_context *ctx,
+ const unsigned char *input,
+ size_t ilen )
+{
+ mbedcrypto_sha256_update_ret( ctx, input, ilen );
+}
+#endif
+
+static const unsigned char sha256_padding[64] =
+{
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * SHA-256 final digest
+ */
+int mbedcrypto_sha256_finish_ret( mbedcrypto_sha256_context *ctx,
+ unsigned char output[32] )
+{
+ int ret;
+ uint32_t last, padn;
+ uint32_t high, low;
+ unsigned char msglen[8];
+
+ high = ( ctx->total[0] >> 29 )
+ | ( ctx->total[1] << 3 );
+ low = ( ctx->total[0] << 3 );
+
+ PUT_UINT32_BE( high, msglen, 0 );
+ PUT_UINT32_BE( low, msglen, 4 );
+
+ last = ctx->total[0] & 0x3F;
+ padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
+
+ if( ( ret = mbedcrypto_sha256_update_ret( ctx, sha256_padding, padn ) ) != 0 )
+ return( ret );
+
+ if( ( ret = mbedcrypto_sha256_update_ret( ctx, msglen, 8 ) ) != 0 )
+ return( ret );
+
+ PUT_UINT32_BE( ctx->state[0], output, 0 );
+ PUT_UINT32_BE( ctx->state[1], output, 4 );
+ PUT_UINT32_BE( ctx->state[2], output, 8 );
+ PUT_UINT32_BE( ctx->state[3], output, 12 );
+ PUT_UINT32_BE( ctx->state[4], output, 16 );
+ PUT_UINT32_BE( ctx->state[5], output, 20 );
+ PUT_UINT32_BE( ctx->state[6], output, 24 );
+
+ if( ctx->is224 == 0 )
+ PUT_UINT32_BE( ctx->state[7], output, 28 );
+
+ return( 0 );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_sha256_finish( mbedcrypto_sha256_context *ctx,
+ unsigned char output[32] )
+{
+ mbedcrypto_sha256_finish_ret( ctx, output );
+}
+#endif
+
+#endif /* !MBEDCRYPTO_SHA256_ALT */
+
+/*
+ * output = SHA-256( input buffer )
+ */
+int mbedcrypto_sha256_ret( const unsigned char *input,
+ size_t ilen,
+ unsigned char output[32],
+ int is224 )
+{
+ int ret;
+ mbedcrypto_sha256_context ctx;
+
+ mbedcrypto_sha256_init( &ctx );
+
+ if( ( ret = mbedcrypto_sha256_starts_ret( &ctx, is224 ) ) != 0 )
+ goto exit;
+
+ if( ( ret = mbedcrypto_sha256_update_ret( &ctx, input, ilen ) ) != 0 )
+ goto exit;
+
+ if( ( ret = mbedcrypto_sha256_finish_ret( &ctx, output ) ) != 0 )
+ goto exit;
+
+exit:
+ mbedcrypto_sha256_free( &ctx );
+
+ return( ret );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_sha256( const unsigned char *input,
+ size_t ilen,
+ unsigned char output[32],
+ int is224 )
+{
+ mbedcrypto_sha256_ret( input, ilen, output, is224 );
+}
+#endif
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+/*
+ * FIPS-180-2 test vectors
+ */
+static const unsigned char sha256_test_buf[3][57] =
+{
+ { "abc" },
+ { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" },
+ { "" }
+};
+
+static const size_t sha256_test_buflen[3] =
+{
+ 3, 56, 1000
+};
+
+static const unsigned char sha256_test_sum[6][32] =
+{
+ /*
+ * SHA-224 test vectors
+ */
+ { 0x23, 0x09, 0x7D, 0x22, 0x34, 0x05, 0xD8, 0x22,
+ 0x86, 0x42, 0xA4, 0x77, 0xBD, 0xA2, 0x55, 0xB3,
+ 0x2A, 0xAD, 0xBC, 0xE4, 0xBD, 0xA0, 0xB3, 0xF7,
+ 0xE3, 0x6C, 0x9D, 0xA7 },
+ { 0x75, 0x38, 0x8B, 0x16, 0x51, 0x27, 0x76, 0xCC,
+ 0x5D, 0xBA, 0x5D, 0xA1, 0xFD, 0x89, 0x01, 0x50,
+ 0xB0, 0xC6, 0x45, 0x5C, 0xB4, 0xF5, 0x8B, 0x19,
+ 0x52, 0x52, 0x25, 0x25 },
+ { 0x20, 0x79, 0x46, 0x55, 0x98, 0x0C, 0x91, 0xD8,
+ 0xBB, 0xB4, 0xC1, 0xEA, 0x97, 0x61, 0x8A, 0x4B,
+ 0xF0, 0x3F, 0x42, 0x58, 0x19, 0x48, 0xB2, 0xEE,
+ 0x4E, 0xE7, 0xAD, 0x67 },
+
+ /*
+ * SHA-256 test vectors
+ */
+ { 0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA,
+ 0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23,
+ 0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C,
+ 0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD },
+ { 0x24, 0x8D, 0x6A, 0x61, 0xD2, 0x06, 0x38, 0xB8,
+ 0xE5, 0xC0, 0x26, 0x93, 0x0C, 0x3E, 0x60, 0x39,
+ 0xA3, 0x3C, 0xE4, 0x59, 0x64, 0xFF, 0x21, 0x67,
+ 0xF6, 0xEC, 0xED, 0xD4, 0x19, 0xDB, 0x06, 0xC1 },
+ { 0xCD, 0xC7, 0x6E, 0x5C, 0x99, 0x14, 0xFB, 0x92,
+ 0x81, 0xA1, 0xC7, 0xE2, 0x84, 0xD7, 0x3E, 0x67,
+ 0xF1, 0x80, 0x9A, 0x48, 0xA4, 0x97, 0x20, 0x0E,
+ 0x04, 0x6D, 0x39, 0xCC, 0xC7, 0x11, 0x2C, 0xD0 }
+};
+
+/*
+ * Checkup routine
+ */
+int mbedcrypto_sha256_self_test( int verbose )
+{
+ int i, j, k, buflen, ret = 0;
+ unsigned char *buf;
+ unsigned char sha256sum[32];
+ mbedcrypto_sha256_context ctx;
+
+ buf = mbedcrypto_calloc( 1024, sizeof(unsigned char) );
+ if( NULL == buf )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( "Buffer allocation failed\n" );
+
+ return( 1 );
+ }
+
+ mbedcrypto_sha256_init( &ctx );
+
+ for( i = 0; i < 6; i++ )
+ {
+ j = i % 3;
+ k = i < 3;
+
+ if( verbose != 0 )
+ mbedcrypto_printf( " SHA-%d test #%d: ", 256 - k * 32, j + 1 );
+
+ if( ( ret = mbedcrypto_sha256_starts_ret( &ctx, k ) ) != 0 )
+ goto fail;
+
+ if( j == 2 )
+ {
+ memset( buf, 'a', buflen = 1000 );
+
+ for( j = 0; j < 1000; j++ )
+ {
+ ret = mbedcrypto_sha256_update_ret( &ctx, buf, buflen );
+ if( ret != 0 )
+ goto fail;
+ }
+
+ }
+ else
+ {
+ ret = mbedcrypto_sha256_update_ret( &ctx, sha256_test_buf[j],
+ sha256_test_buflen[j] );
+ if( ret != 0 )
+ goto fail;
+ }
+
+ if( ( ret = mbedcrypto_sha256_finish_ret( &ctx, sha256sum ) ) != 0 )
+ goto fail;
+
+
+ if( memcmp( sha256sum, sha256_test_sum[i], 32 - k * 4 ) != 0 )
+ {
+ ret = 1;
+ goto fail;
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "\n" );
+
+ goto exit;
+
+fail:
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+
+exit:
+ mbedcrypto_sha256_free( &ctx );
+ mbedcrypto_free( buf );
+
+ return( ret );
+}
+
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#endif /* MBEDCRYPTO_SHA256_C */
diff --git a/library/sha512.c b/library/sha512.c
new file mode 100644
index 0000000..10aac33
--- /dev/null
+++ b/library/sha512.c
@@ -0,0 +1,600 @@
+/*
+ * FIPS-180-2 compliant SHA-384/512 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 Crypto (https://tls.mbed.org)
+ */
+/*
+ * The SHA-512 Secure Hash Standard was published by NIST in 2002.
+ *
+ * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_SHA512_C)
+
+#include "mbedcrypto/sha512.h"
+#include "mbedcrypto/platform_util.h"
+
+#if defined(_MSC_VER) || defined(__WATCOMC__)
+ #define UL64(x) x##ui64
+#else
+ #define UL64(x) x##ULL
+#endif
+
+#include <string.h>
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#define mbedcrypto_printf printf
+#define mbedcrypto_calloc calloc
+#define mbedcrypto_free free
+#endif /* MBEDCRYPTO_PLATFORM_C */
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#if !defined(MBEDCRYPTO_SHA512_ALT)
+
+/*
+ * 64-bit integer manipulation macros (big endian)
+ */
+#ifndef GET_UINT64_BE
+#define GET_UINT64_BE(n,b,i) \
+{ \
+ (n) = ( (uint64_t) (b)[(i) ] << 56 ) \
+ | ( (uint64_t) (b)[(i) + 1] << 48 ) \
+ | ( (uint64_t) (b)[(i) + 2] << 40 ) \
+ | ( (uint64_t) (b)[(i) + 3] << 32 ) \
+ | ( (uint64_t) (b)[(i) + 4] << 24 ) \
+ | ( (uint64_t) (b)[(i) + 5] << 16 ) \
+ | ( (uint64_t) (b)[(i) + 6] << 8 ) \
+ | ( (uint64_t) (b)[(i) + 7] ); \
+}
+#endif /* GET_UINT64_BE */
+
+#ifndef PUT_UINT64_BE
+#define PUT_UINT64_BE(n,b,i) \
+{ \
+ (b)[(i) ] = (unsigned char) ( (n) >> 56 ); \
+ (b)[(i) + 1] = (unsigned char) ( (n) >> 48 ); \
+ (b)[(i) + 2] = (unsigned char) ( (n) >> 40 ); \
+ (b)[(i) + 3] = (unsigned char) ( (n) >> 32 ); \
+ (b)[(i) + 4] = (unsigned char) ( (n) >> 24 ); \
+ (b)[(i) + 5] = (unsigned char) ( (n) >> 16 ); \
+ (b)[(i) + 6] = (unsigned char) ( (n) >> 8 ); \
+ (b)[(i) + 7] = (unsigned char) ( (n) ); \
+}
+#endif /* PUT_UINT64_BE */
+
+void mbedcrypto_sha512_init( mbedcrypto_sha512_context *ctx )
+{
+ memset( ctx, 0, sizeof( mbedcrypto_sha512_context ) );
+}
+
+void mbedcrypto_sha512_free( mbedcrypto_sha512_context *ctx )
+{
+ if( ctx == NULL )
+ return;
+
+ mbedcrypto_platform_zeroize( ctx, sizeof( mbedcrypto_sha512_context ) );
+}
+
+void mbedcrypto_sha512_clone( mbedcrypto_sha512_context *dst,
+ const mbedcrypto_sha512_context *src )
+{
+ *dst = *src;
+}
+
+/*
+ * SHA-512 context setup
+ */
+int mbedcrypto_sha512_starts_ret( mbedcrypto_sha512_context *ctx, int is384 )
+{
+ ctx->total[0] = 0;
+ ctx->total[1] = 0;
+
+ if( is384 == 0 )
+ {
+ /* SHA-512 */
+ ctx->state[0] = UL64(0x6A09E667F3BCC908);
+ ctx->state[1] = UL64(0xBB67AE8584CAA73B);
+ ctx->state[2] = UL64(0x3C6EF372FE94F82B);
+ ctx->state[3] = UL64(0xA54FF53A5F1D36F1);
+ ctx->state[4] = UL64(0x510E527FADE682D1);
+ ctx->state[5] = UL64(0x9B05688C2B3E6C1F);
+ ctx->state[6] = UL64(0x1F83D9ABFB41BD6B);
+ ctx->state[7] = UL64(0x5BE0CD19137E2179);
+ }
+ else
+ {
+ /* SHA-384 */
+ ctx->state[0] = UL64(0xCBBB9D5DC1059ED8);
+ ctx->state[1] = UL64(0x629A292A367CD507);
+ ctx->state[2] = UL64(0x9159015A3070DD17);
+ ctx->state[3] = UL64(0x152FECD8F70E5939);
+ ctx->state[4] = UL64(0x67332667FFC00B31);
+ ctx->state[5] = UL64(0x8EB44A8768581511);
+ ctx->state[6] = UL64(0xDB0C2E0D64F98FA7);
+ ctx->state[7] = UL64(0x47B5481DBEFA4FA4);
+ }
+
+ ctx->is384 = is384;
+
+ return( 0 );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_sha512_starts( mbedcrypto_sha512_context *ctx,
+ int is384 )
+{
+ mbedcrypto_sha512_starts_ret( ctx, is384 );
+}
+#endif
+
+#if !defined(MBEDCRYPTO_SHA512_PROCESS_ALT)
+
+/*
+ * Round constants
+ */
+static const uint64_t K[80] =
+{
+ UL64(0x428A2F98D728AE22), UL64(0x7137449123EF65CD),
+ UL64(0xB5C0FBCFEC4D3B2F), UL64(0xE9B5DBA58189DBBC),
+ UL64(0x3956C25BF348B538), UL64(0x59F111F1B605D019),
+ UL64(0x923F82A4AF194F9B), UL64(0xAB1C5ED5DA6D8118),
+ UL64(0xD807AA98A3030242), UL64(0x12835B0145706FBE),
+ UL64(0x243185BE4EE4B28C), UL64(0x550C7DC3D5FFB4E2),
+ UL64(0x72BE5D74F27B896F), UL64(0x80DEB1FE3B1696B1),
+ UL64(0x9BDC06A725C71235), UL64(0xC19BF174CF692694),
+ UL64(0xE49B69C19EF14AD2), UL64(0xEFBE4786384F25E3),
+ UL64(0x0FC19DC68B8CD5B5), UL64(0x240CA1CC77AC9C65),
+ UL64(0x2DE92C6F592B0275), UL64(0x4A7484AA6EA6E483),
+ UL64(0x5CB0A9DCBD41FBD4), UL64(0x76F988DA831153B5),
+ UL64(0x983E5152EE66DFAB), UL64(0xA831C66D2DB43210),
+ UL64(0xB00327C898FB213F), UL64(0xBF597FC7BEEF0EE4),
+ UL64(0xC6E00BF33DA88FC2), UL64(0xD5A79147930AA725),
+ UL64(0x06CA6351E003826F), UL64(0x142929670A0E6E70),
+ UL64(0x27B70A8546D22FFC), UL64(0x2E1B21385C26C926),
+ UL64(0x4D2C6DFC5AC42AED), UL64(0x53380D139D95B3DF),
+ UL64(0x650A73548BAF63DE), UL64(0x766A0ABB3C77B2A8),
+ UL64(0x81C2C92E47EDAEE6), UL64(0x92722C851482353B),
+ UL64(0xA2BFE8A14CF10364), UL64(0xA81A664BBC423001),
+ UL64(0xC24B8B70D0F89791), UL64(0xC76C51A30654BE30),
+ UL64(0xD192E819D6EF5218), UL64(0xD69906245565A910),
+ UL64(0xF40E35855771202A), UL64(0x106AA07032BBD1B8),
+ UL64(0x19A4C116B8D2D0C8), UL64(0x1E376C085141AB53),
+ UL64(0x2748774CDF8EEB99), UL64(0x34B0BCB5E19B48A8),
+ UL64(0x391C0CB3C5C95A63), UL64(0x4ED8AA4AE3418ACB),
+ UL64(0x5B9CCA4F7763E373), UL64(0x682E6FF3D6B2B8A3),
+ UL64(0x748F82EE5DEFB2FC), UL64(0x78A5636F43172F60),
+ UL64(0x84C87814A1F0AB72), UL64(0x8CC702081A6439EC),
+ UL64(0x90BEFFFA23631E28), UL64(0xA4506CEBDE82BDE9),
+ UL64(0xBEF9A3F7B2C67915), UL64(0xC67178F2E372532B),
+ UL64(0xCA273ECEEA26619C), UL64(0xD186B8C721C0C207),
+ UL64(0xEADA7DD6CDE0EB1E), UL64(0xF57D4F7FEE6ED178),
+ UL64(0x06F067AA72176FBA), UL64(0x0A637DC5A2C898A6),
+ UL64(0x113F9804BEF90DAE), UL64(0x1B710B35131C471B),
+ UL64(0x28DB77F523047D84), UL64(0x32CAAB7B40C72493),
+ UL64(0x3C9EBE0A15C9BEBC), UL64(0x431D67C49C100D4C),
+ UL64(0x4CC5D4BECB3E42B6), UL64(0x597F299CFC657E2A),
+ UL64(0x5FCB6FAB3AD6FAEC), UL64(0x6C44198C4A475817)
+};
+
+int mbedcrypto_internal_sha512_process( mbedcrypto_sha512_context *ctx,
+ const unsigned char data[128] )
+{
+ int i;
+ uint64_t temp1, temp2, W[80];
+ uint64_t A, B, C, D, E, F, G, H;
+
+#define SHR(x,n) (x >> n)
+#define ROTR(x,n) (SHR(x,n) | (x << (64 - n)))
+
+#define S0(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHR(x, 7))
+#define S1(x) (ROTR(x,19) ^ ROTR(x,61) ^ SHR(x, 6))
+
+#define S2(x) (ROTR(x,28) ^ ROTR(x,34) ^ ROTR(x,39))
+#define S3(x) (ROTR(x,14) ^ ROTR(x,18) ^ ROTR(x,41))
+
+#define F0(x,y,z) ((x & y) | (z & (x | y)))
+#define F1(x,y,z) (z ^ (x & (y ^ z)))
+
+#define P(a,b,c,d,e,f,g,h,x,K) \
+{ \
+ temp1 = h + S3(e) + F1(e,f,g) + K + x; \
+ temp2 = S2(a) + F0(a,b,c); \
+ d += temp1; h = temp1 + temp2; \
+}
+
+ for( i = 0; i < 16; i++ )
+ {
+ GET_UINT64_BE( W[i], data, i << 3 );
+ }
+
+ for( ; i < 80; i++ )
+ {
+ W[i] = S1(W[i - 2]) + W[i - 7] +
+ S0(W[i - 15]) + W[i - 16];
+ }
+
+ A = ctx->state[0];
+ B = ctx->state[1];
+ C = ctx->state[2];
+ D = ctx->state[3];
+ E = ctx->state[4];
+ F = ctx->state[5];
+ G = ctx->state[6];
+ H = ctx->state[7];
+ i = 0;
+
+ do
+ {
+ P( A, B, C, D, E, F, G, H, W[i], K[i] ); i++;
+ P( H, A, B, C, D, E, F, G, W[i], K[i] ); i++;
+ P( G, H, A, B, C, D, E, F, W[i], K[i] ); i++;
+ P( F, G, H, A, B, C, D, E, W[i], K[i] ); i++;
+ P( E, F, G, H, A, B, C, D, W[i], K[i] ); i++;
+ P( D, E, F, G, H, A, B, C, W[i], K[i] ); i++;
+ P( C, D, E, F, G, H, A, B, W[i], K[i] ); i++;
+ P( B, C, D, E, F, G, H, A, W[i], K[i] ); i++;
+ }
+ while( i < 80 );
+
+ ctx->state[0] += A;
+ ctx->state[1] += B;
+ ctx->state[2] += C;
+ ctx->state[3] += D;
+ ctx->state[4] += E;
+ ctx->state[5] += F;
+ ctx->state[6] += G;
+ ctx->state[7] += H;
+
+ return( 0 );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_sha512_process( mbedcrypto_sha512_context *ctx,
+ const unsigned char data[128] )
+{
+ mbedcrypto_internal_sha512_process( ctx, data );
+}
+#endif
+#endif /* !MBEDCRYPTO_SHA512_PROCESS_ALT */
+
+/*
+ * SHA-512 process buffer
+ */
+int mbedcrypto_sha512_update_ret( mbedcrypto_sha512_context *ctx,
+ const unsigned char *input,
+ size_t ilen )
+{
+ int ret;
+ size_t fill;
+ unsigned int left;
+
+ if( ilen == 0 )
+ return( 0 );
+
+ left = (unsigned int) (ctx->total[0] & 0x7F);
+ fill = 128 - left;
+
+ ctx->total[0] += (uint64_t) ilen;
+
+ if( ctx->total[0] < (uint64_t) ilen )
+ ctx->total[1]++;
+
+ if( left && ilen >= fill )
+ {
+ memcpy( (void *) (ctx->buffer + left), input, fill );
+
+ if( ( ret = mbedcrypto_internal_sha512_process( ctx, ctx->buffer ) ) != 0 )
+ return( ret );
+
+ input += fill;
+ ilen -= fill;
+ left = 0;
+ }
+
+ while( ilen >= 128 )
+ {
+ if( ( ret = mbedcrypto_internal_sha512_process( ctx, input ) ) != 0 )
+ return( ret );
+
+ input += 128;
+ ilen -= 128;
+ }
+
+ if( ilen > 0 )
+ memcpy( (void *) (ctx->buffer + left), input, ilen );
+
+ return( 0 );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_sha512_update( mbedcrypto_sha512_context *ctx,
+ const unsigned char *input,
+ size_t ilen )
+{
+ mbedcrypto_sha512_update_ret( ctx, input, ilen );
+}
+#endif
+
+static const unsigned char sha512_padding[128] =
+{
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * SHA-512 final digest
+ */
+int mbedcrypto_sha512_finish_ret( mbedcrypto_sha512_context *ctx,
+ unsigned char output[64] )
+{
+ int ret;
+ size_t last, padn;
+ uint64_t high, low;
+ unsigned char msglen[16];
+
+ high = ( ctx->total[0] >> 61 )
+ | ( ctx->total[1] << 3 );
+ low = ( ctx->total[0] << 3 );
+
+ PUT_UINT64_BE( high, msglen, 0 );
+ PUT_UINT64_BE( low, msglen, 8 );
+
+ last = (size_t)( ctx->total[0] & 0x7F );
+ padn = ( last < 112 ) ? ( 112 - last ) : ( 240 - last );
+
+ if( ( ret = mbedcrypto_sha512_update_ret( ctx, sha512_padding, padn ) ) != 0 )
+ return( ret );
+
+ if( ( ret = mbedcrypto_sha512_update_ret( ctx, msglen, 16 ) ) != 0 )
+ return( ret );
+
+ PUT_UINT64_BE( ctx->state[0], output, 0 );
+ PUT_UINT64_BE( ctx->state[1], output, 8 );
+ PUT_UINT64_BE( ctx->state[2], output, 16 );
+ PUT_UINT64_BE( ctx->state[3], output, 24 );
+ PUT_UINT64_BE( ctx->state[4], output, 32 );
+ PUT_UINT64_BE( ctx->state[5], output, 40 );
+
+ if( ctx->is384 == 0 )
+ {
+ PUT_UINT64_BE( ctx->state[6], output, 48 );
+ PUT_UINT64_BE( ctx->state[7], output, 56 );
+ }
+
+ return( 0 );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_sha512_finish( mbedcrypto_sha512_context *ctx,
+ unsigned char output[64] )
+{
+ mbedcrypto_sha512_finish_ret( ctx, output );
+}
+#endif
+
+#endif /* !MBEDCRYPTO_SHA512_ALT */
+
+/*
+ * output = SHA-512( input buffer )
+ */
+int mbedcrypto_sha512_ret( const unsigned char *input,
+ size_t ilen,
+ unsigned char output[64],
+ int is384 )
+{
+ int ret;
+ mbedcrypto_sha512_context ctx;
+
+ mbedcrypto_sha512_init( &ctx );
+
+ if( ( ret = mbedcrypto_sha512_starts_ret( &ctx, is384 ) ) != 0 )
+ goto exit;
+
+ if( ( ret = mbedcrypto_sha512_update_ret( &ctx, input, ilen ) ) != 0 )
+ goto exit;
+
+ if( ( ret = mbedcrypto_sha512_finish_ret( &ctx, output ) ) != 0 )
+ goto exit;
+
+exit:
+ mbedcrypto_sha512_free( &ctx );
+
+ return( ret );
+}
+
+#if !defined(MBEDCRYPTO_DEPRECATED_REMOVED)
+void mbedcrypto_sha512( const unsigned char *input,
+ size_t ilen,
+ unsigned char output[64],
+ int is384 )
+{
+ mbedcrypto_sha512_ret( input, ilen, output, is384 );
+}
+#endif
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+
+/*
+ * FIPS-180-2 test vectors
+ */
+static const unsigned char sha512_test_buf[3][113] =
+{
+ { "abc" },
+ { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
+ "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" },
+ { "" }
+};
+
+static const size_t sha512_test_buflen[3] =
+{
+ 3, 112, 1000
+};
+
+static const unsigned char sha512_test_sum[6][64] =
+{
+ /*
+ * SHA-384 test vectors
+ */
+ { 0xCB, 0x00, 0x75, 0x3F, 0x45, 0xA3, 0x5E, 0x8B,
+ 0xB5, 0xA0, 0x3D, 0x69, 0x9A, 0xC6, 0x50, 0x07,
+ 0x27, 0x2C, 0x32, 0xAB, 0x0E, 0xDE, 0xD1, 0x63,
+ 0x1A, 0x8B, 0x60, 0x5A, 0x43, 0xFF, 0x5B, 0xED,
+ 0x80, 0x86, 0x07, 0x2B, 0xA1, 0xE7, 0xCC, 0x23,
+ 0x58, 0xBA, 0xEC, 0xA1, 0x34, 0xC8, 0x25, 0xA7 },
+ { 0x09, 0x33, 0x0C, 0x33, 0xF7, 0x11, 0x47, 0xE8,
+ 0x3D, 0x19, 0x2F, 0xC7, 0x82, 0xCD, 0x1B, 0x47,
+ 0x53, 0x11, 0x1B, 0x17, 0x3B, 0x3B, 0x05, 0xD2,
+ 0x2F, 0xA0, 0x80, 0x86, 0xE3, 0xB0, 0xF7, 0x12,
+ 0xFC, 0xC7, 0xC7, 0x1A, 0x55, 0x7E, 0x2D, 0xB9,
+ 0x66, 0xC3, 0xE9, 0xFA, 0x91, 0x74, 0x60, 0x39 },
+ { 0x9D, 0x0E, 0x18, 0x09, 0x71, 0x64, 0x74, 0xCB,
+ 0x08, 0x6E, 0x83, 0x4E, 0x31, 0x0A, 0x4A, 0x1C,
+ 0xED, 0x14, 0x9E, 0x9C, 0x00, 0xF2, 0x48, 0x52,
+ 0x79, 0x72, 0xCE, 0xC5, 0x70, 0x4C, 0x2A, 0x5B,
+ 0x07, 0xB8, 0xB3, 0xDC, 0x38, 0xEC, 0xC4, 0xEB,
+ 0xAE, 0x97, 0xDD, 0xD8, 0x7F, 0x3D, 0x89, 0x85 },
+
+ /*
+ * SHA-512 test vectors
+ */
+ { 0xDD, 0xAF, 0x35, 0xA1, 0x93, 0x61, 0x7A, 0xBA,
+ 0xCC, 0x41, 0x73, 0x49, 0xAE, 0x20, 0x41, 0x31,
+ 0x12, 0xE6, 0xFA, 0x4E, 0x89, 0xA9, 0x7E, 0xA2,
+ 0x0A, 0x9E, 0xEE, 0xE6, 0x4B, 0x55, 0xD3, 0x9A,
+ 0x21, 0x92, 0x99, 0x2A, 0x27, 0x4F, 0xC1, 0xA8,
+ 0x36, 0xBA, 0x3C, 0x23, 0xA3, 0xFE, 0xEB, 0xBD,
+ 0x45, 0x4D, 0x44, 0x23, 0x64, 0x3C, 0xE8, 0x0E,
+ 0x2A, 0x9A, 0xC9, 0x4F, 0xA5, 0x4C, 0xA4, 0x9F },
+ { 0x8E, 0x95, 0x9B, 0x75, 0xDA, 0xE3, 0x13, 0xDA,
+ 0x8C, 0xF4, 0xF7, 0x28, 0x14, 0xFC, 0x14, 0x3F,
+ 0x8F, 0x77, 0x79, 0xC6, 0xEB, 0x9F, 0x7F, 0xA1,
+ 0x72, 0x99, 0xAE, 0xAD, 0xB6, 0x88, 0x90, 0x18,
+ 0x50, 0x1D, 0x28, 0x9E, 0x49, 0x00, 0xF7, 0xE4,
+ 0x33, 0x1B, 0x99, 0xDE, 0xC4, 0xB5, 0x43, 0x3A,
+ 0xC7, 0xD3, 0x29, 0xEE, 0xB6, 0xDD, 0x26, 0x54,
+ 0x5E, 0x96, 0xE5, 0x5B, 0x87, 0x4B, 0xE9, 0x09 },
+ { 0xE7, 0x18, 0x48, 0x3D, 0x0C, 0xE7, 0x69, 0x64,
+ 0x4E, 0x2E, 0x42, 0xC7, 0xBC, 0x15, 0xB4, 0x63,
+ 0x8E, 0x1F, 0x98, 0xB1, 0x3B, 0x20, 0x44, 0x28,
+ 0x56, 0x32, 0xA8, 0x03, 0xAF, 0xA9, 0x73, 0xEB,
+ 0xDE, 0x0F, 0xF2, 0x44, 0x87, 0x7E, 0xA6, 0x0A,
+ 0x4C, 0xB0, 0x43, 0x2C, 0xE5, 0x77, 0xC3, 0x1B,
+ 0xEB, 0x00, 0x9C, 0x5C, 0x2C, 0x49, 0xAA, 0x2E,
+ 0x4E, 0xAD, 0xB2, 0x17, 0xAD, 0x8C, 0xC0, 0x9B }
+};
+
+/*
+ * Checkup routine
+ */
+int mbedcrypto_sha512_self_test( int verbose )
+{
+ int i, j, k, buflen, ret = 0;
+ unsigned char *buf;
+ unsigned char sha512sum[64];
+ mbedcrypto_sha512_context ctx;
+
+ buf = mbedcrypto_calloc( 1024, sizeof(unsigned char) );
+ if( NULL == buf )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( "Buffer allocation failed\n" );
+
+ return( 1 );
+ }
+
+ mbedcrypto_sha512_init( &ctx );
+
+ for( i = 0; i < 6; i++ )
+ {
+ j = i % 3;
+ k = i < 3;
+
+ if( verbose != 0 )
+ mbedcrypto_printf( " SHA-%d test #%d: ", 512 - k * 128, j + 1 );
+
+ if( ( ret = mbedcrypto_sha512_starts_ret( &ctx, k ) ) != 0 )
+ goto fail;
+
+ if( j == 2 )
+ {
+ memset( buf, 'a', buflen = 1000 );
+
+ for( j = 0; j < 1000; j++ )
+ {
+ ret = mbedcrypto_sha512_update_ret( &ctx, buf, buflen );
+ if( ret != 0 )
+ goto fail;
+ }
+ }
+ else
+ {
+ ret = mbedcrypto_sha512_update_ret( &ctx, sha512_test_buf[j],
+ sha512_test_buflen[j] );
+ if( ret != 0 )
+ goto fail;
+ }
+
+ if( ( ret = mbedcrypto_sha512_finish_ret( &ctx, sha512sum ) ) != 0 )
+ goto fail;
+
+ if( memcmp( sha512sum, sha512_test_sum[i], 64 - k * 16 ) != 0 )
+ {
+ ret = 1;
+ goto fail;
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "\n" );
+
+ goto exit;
+
+fail:
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+
+exit:
+ mbedcrypto_sha512_free( &ctx );
+ mbedcrypto_free( buf );
+
+ return( ret );
+}
+
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#endif /* MBEDCRYPTO_SHA512_C */
diff --git a/library/xtea.c b/library/xtea.c
new file mode 100644
index 0000000..aa45819
--- /dev/null
+++ b/library/xtea.c
@@ -0,0 +1,277 @@
+/*
+ * An 32-bit implementation of the XTEA 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 Crypto (https://tls.mbed.org)
+ */
+
+#if !defined(MBEDCRYPTO_CONFIG_FILE)
+#include "mbedcrypto/config.h"
+#else
+#include MBEDCRYPTO_CONFIG_FILE
+#endif
+
+#if defined(MBEDCRYPTO_XTEA_C)
+
+#include "mbedcrypto/xtea.h"
+#include "mbedcrypto/platform_util.h"
+
+#include <string.h>
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+#if defined(MBEDCRYPTO_PLATFORM_C)
+#include "mbedcrypto/platform.h"
+#else
+#include <stdio.h>
+#define mbedcrypto_printf printf
+#endif /* MBEDCRYPTO_PLATFORM_C */
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#if !defined(MBEDCRYPTO_XTEA_ALT)
+
+/*
+ * 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
+
+void mbedcrypto_xtea_init( mbedcrypto_xtea_context *ctx )
+{
+ memset( ctx, 0, sizeof( mbedcrypto_xtea_context ) );
+}
+
+void mbedcrypto_xtea_free( mbedcrypto_xtea_context *ctx )
+{
+ if( ctx == NULL )
+ return;
+
+ mbedcrypto_platform_zeroize( ctx, sizeof( mbedcrypto_xtea_context ) );
+}
+
+/*
+ * XTEA key schedule
+ */
+void mbedcrypto_xtea_setup( mbedcrypto_xtea_context *ctx, const unsigned char key[16] )
+{
+ int i;
+
+ memset( ctx, 0, sizeof(mbedcrypto_xtea_context) );
+
+ for( i = 0; i < 4; i++ )
+ {
+ GET_UINT32_BE( ctx->k[i], key, i << 2 );
+ }
+}
+
+/*
+ * XTEA encrypt function
+ */
+int mbedcrypto_xtea_crypt_ecb( mbedcrypto_xtea_context *ctx, int mode,
+ const unsigned char input[8], unsigned char output[8])
+{
+ uint32_t *k, v0, v1, i;
+
+ k = ctx->k;
+
+ GET_UINT32_BE( v0, input, 0 );
+ GET_UINT32_BE( v1, input, 4 );
+
+ if( mode == MBEDCRYPTO_XTEA_ENCRYPT )
+ {
+ uint32_t sum = 0, delta = 0x9E3779B9;
+
+ for( i = 0; i < 32; i++ )
+ {
+ v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]);
+ sum += delta;
+ v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum>>11) & 3]);
+ }
+ }
+ else /* MBEDCRYPTO_XTEA_DECRYPT */
+ {
+ uint32_t delta = 0x9E3779B9, sum = delta * 32;
+
+ for( i = 0; i < 32; i++ )
+ {
+ v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum>>11) & 3]);
+ sum -= delta;
+ v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]);
+ }
+ }
+
+ PUT_UINT32_BE( v0, output, 0 );
+ PUT_UINT32_BE( v1, output, 4 );
+
+ return( 0 );
+}
+
+#if defined(MBEDCRYPTO_CIPHER_MODE_CBC)
+/*
+ * XTEA-CBC buffer encryption/decryption
+ */
+int mbedcrypto_xtea_crypt_cbc( mbedcrypto_xtea_context *ctx, int mode, size_t length,
+ unsigned char iv[8], const unsigned char *input,
+ unsigned char *output)
+{
+ int i;
+ unsigned char temp[8];
+
+ if( length % 8 )
+ return( MBEDCRYPTO_ERR_XTEA_INVALID_INPUT_LENGTH );
+
+ if( mode == MBEDCRYPTO_XTEA_DECRYPT )
+ {
+ while( length > 0 )
+ {
+ memcpy( temp, input, 8 );
+ mbedcrypto_xtea_crypt_ecb( ctx, mode, input, output );
+
+ for( i = 0; i < 8; i++ )
+ output[i] = (unsigned char)( output[i] ^ iv[i] );
+
+ memcpy( iv, temp, 8 );
+
+ input += 8;
+ output += 8;
+ length -= 8;
+ }
+ }
+ else
+ {
+ while( length > 0 )
+ {
+ for( i = 0; i < 8; i++ )
+ output[i] = (unsigned char)( input[i] ^ iv[i] );
+
+ mbedcrypto_xtea_crypt_ecb( ctx, mode, output, output );
+ memcpy( iv, output, 8 );
+
+ input += 8;
+ output += 8;
+ length -= 8;
+ }
+ }
+
+ return( 0 );
+}
+#endif /* MBEDCRYPTO_CIPHER_MODE_CBC */
+#endif /* !MBEDCRYPTO_XTEA_ALT */
+
+#if defined(MBEDCRYPTO_SELF_TEST)
+
+/*
+ * XTEA tests vectors (non-official)
+ */
+
+static const unsigned char xtea_test_key[6][16] =
+{
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+ 0x0c, 0x0d, 0x0e, 0x0f },
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+ 0x0c, 0x0d, 0x0e, 0x0f },
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+ 0x0c, 0x0d, 0x0e, 0x0f },
+ { 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 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00 }
+};
+
+static const unsigned char xtea_test_pt[6][8] =
+{
+ { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48 },
+ { 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 },
+ { 0x5a, 0x5b, 0x6e, 0x27, 0x89, 0x48, 0xd7, 0x7f },
+ { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48 },
+ { 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 },
+ { 0x70, 0xe1, 0x22, 0x5d, 0x6e, 0x4e, 0x76, 0x55 }
+};
+
+static const unsigned char xtea_test_ct[6][8] =
+{
+ { 0x49, 0x7d, 0xf3, 0xd0, 0x72, 0x61, 0x2c, 0xb5 },
+ { 0xe7, 0x8f, 0x2d, 0x13, 0x74, 0x43, 0x41, 0xd8 },
+ { 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 },
+ { 0xa0, 0x39, 0x05, 0x89, 0xf8, 0xb8, 0xef, 0xa5 },
+ { 0xed, 0x23, 0x37, 0x5a, 0x82, 0x1a, 0x8c, 0x2d },
+ { 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 }
+};
+
+/*
+ * Checkup routine
+ */
+int mbedcrypto_xtea_self_test( int verbose )
+{
+ int i, ret = 0;
+ unsigned char buf[8];
+ mbedcrypto_xtea_context ctx;
+
+ mbedcrypto_xtea_init( &ctx );
+ for( i = 0; i < 6; i++ )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( " XTEA test #%d: ", i + 1 );
+
+ memcpy( buf, xtea_test_pt[i], 8 );
+
+ mbedcrypto_xtea_setup( &ctx, xtea_test_key[i] );
+ mbedcrypto_xtea_crypt_ecb( &ctx, MBEDCRYPTO_XTEA_ENCRYPT, buf, buf );
+
+ if( memcmp( buf, xtea_test_ct[i], 8 ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedcrypto_printf( "failed\n" );
+
+ ret = 1;
+ goto exit;
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "passed\n" );
+ }
+
+ if( verbose != 0 )
+ mbedcrypto_printf( "\n" );
+
+exit:
+ mbedcrypto_xtea_free( &ctx );
+
+ return( ret );
+}
+
+#endif /* MBEDCRYPTO_SELF_TEST */
+
+#endif /* MBEDCRYPTO_XTEA_C */