/*************************************************************************** * Copyright 2013 CertiVox UK Ltd. * * This file is part of CertiVox MIRACL Crypto SDK. * * The CertiVox MIRACL Crypto SDK provides developers with an * extensive and efficient set of cryptographic functions. * For further information about its features and functionalities please * refer to http://www.certivox.com * * * The CertiVox MIRACL Crypto SDK is free software: you can * redistribute it and/or modify it under the terms of the * GNU Affero General Public License as published by the * Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * * The CertiVox MIRACL Crypto SDK is distributed in the hope * that it will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * * * You should have received a copy of the GNU Affero General Public * License along with CertiVox MIRACL Crypto SDK. * If not, see . * * You can be released from the requirements of the license by purchasing * a commercial license. Buying such a license is mandatory as soon as you * develop commercial activities involving the CertiVox MIRACL Crypto SDK * without disclosing the source code of your own applications, or shipping * the CertiVox MIRACL Crypto SDK with a closed source product. * * ***************************************************************************/ /* * Implementation of BPS Format Preserving Encryption * * See "BPS: a Format Preserving Encryption Proposal" by E. Brier, T. Peyrin and J. Stern * * http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/bps/bps-spec.pdf * * Uses AES internally * * Author: M. Scott 2012/2015 */ #include #include "miracl.h" /* Define FPE_TEST to activate test main program and run test vectors */ /* Link with mraes.c */ /* gcc -O2 mrfpe.c mraes.c -o mrfpe.exe */ /* #define FPE_TEST */ #define UINT32 mr_unsign32 /* 32-bit unsigned type */ #define W 8 /* recommended number of rounds */ #define BLOCK_SIZE 16 /* 16 Byte Blocks - AES */ #define ENCRYPT 0 #define DECRYPT 1 static void unpack(UINT32 a,MR_BYTE *b) { /* unpack bytes from a word */ b[0]=MR_TOBYTE(a); b[1]=MR_TOBYTE(a>>8); b[2]=MR_TOBYTE(a>>16); b[3]=MR_TOBYTE(a>>24); } /* Little Endian */ static int to_base_256(char *x,int len,int s,MR_BYTE *y) { /* x[] of length len to base s is converted to byte array y[] of length BLOCK_SIZE */ int i,j,m; UINT32 c; for (i=0;i=0;j--) { /* multiply by s */ c=x[j]; for (i=0;i>=8; } if (c>0) {m++; y[m-1]=c;} } return m; } /* Find max_b for chosen cipher and number base */ static int maxb(int s) { MR_BYTE y[BLOCK_SIZE]; int i,m,n,c; if (s==2) return 192; m=1; y[0]=1; for (n=0;;n++) { c=0; for (i=0;i>=8; } if (c>0) {m++; y[m-1]=c;} if (m==13) break; /* greater than 2^96 for AES */ } return 2*n; } static void from_base_256(int addsub,MR_BYTE *y,int len,int s,char *x) { /* y[] of length BLOCK_SIZE is added to or subtracted from base s array x[] of length len. */ int i,m,n; UINT32 c,d; m=BLOCK_SIZE; n=0; c=0; forever { while (m>0 && y[m-1]==0) m--; d=0; for (i=m-1;i>=0;i--) { /* divide y by s */ d=(d<<8)+y[i]; y[i]=d/s; d%=s; } if (addsub==ENCRYPT) { /* ADD */ d+=c+x[n]; c=0; if ((int)d>=s) {c=1; x[n]=d-s;} else x[n]=d; } else { /* SUB */ d+=c; c=0; if ((UINT32)x[n]>=d) x[n]-=d; else {x[n]+=(s-d); c=1;} } n++; if (n>=len) break; } } /* AES instance must be initialised and passed */ /* Format Preserving Encryption/Decryption routine */ /* Array x of length len to base s is encrypted/decrypted in place */ static void BC(int crypt,char *x,int len,int s,aes *a,UINT32 TL,UINT32 TR) { int i,j; char *left,*right; MR_BYTE buff[BLOCK_SIZE]; int l,r; l=r=len/2; if (len%2==1) l++; left=&x[0]; right=&x[l]; for (i=0;i=mb) { if (i!=0) for (j=c;j