Embedded src 0001 - JohnHau/mis GitHub Wiki
//itimer.c====================================================================== #include<stdio.h> #include<stdlib.h> #include<string.h> #include<sys/types.h> #include<sys/stat.h> #include<sys/time.h> #include<unistd.h> #include<pthread.h> #include<sys/select.h>
typedef struct plant_pot {
uint32_t version;
float env_temperature;
float env_moisture;
float soil_temperature;
float soil_moisture;
}PLANT_POT_t;
#define NUM_PLANT_POT 8 PLANT_POT_t pp[NUM_PLANT_POT] = {0};
void on_timer(int signum) { static int c =0; if(signum == SIGALRM) { printf("on timer %d\n",c++); } }
int set_ticker(int msec) { struct itimerval new_timerset; long sec,usec;
sec = msec/1000;
usec = (msec%1000)*1000L;
new_timerset.it_interval.tv_sec = sec;
new_timerset.it_interval.tv_usec = usec;
new_timerset.it_value.tv_sec = sec;
new_timerset.it_value.tv_usec = usec;
return setitimer(ITIMER_REAL,&new_timerset,NULL);
}
int32_t get_sec_val(char*s) { int32_t val = -1; if(s == NULL) { return -1; }
if(strlen(s) >= 25)
{
if(s[17] >= 0x30 && s[17] <= 0x39 && s[18] >= 0x30 && s[18] <= 0x39 )
{
val = (s[17]-0x30)*10 + (s[18] - 0x30);
}
}
return -1;
}
void* send_data(void* arg) { while(1) {
time_t t = time(NULL);
char* s = ctime(&t);
int32_t val = get_sec_val(s);
printf("sec is %d\n",val);
printf("s len is %d\n",strlen(s));
printf("send data\n");
printf("time is %s\n",s);
sleep(1);
}
}
void* recv_data(void* arg) { while(1) { printf("recv data\n"); sleep(1);
}
}
float get_fp_rand_number(float n) {
return ((float)rand()/(float)(RAND_MAX)*n);
}
void* read_plant_pot_data(void* arg) {
int i =0;
while(1)
{
for(i=0; i< NUM_PLANT_POT; i++)
{
pp[i].version = 1;
pp[i].env_temperature = 25.8;
pp[i].env_moisture = 54.2;
pp[i].soil_temperature = 25.9;
pp[i].soil_moisture = 65.6;
}
sleep(10);
}
}
int main(int argc, char* argv[]) { for(int i=0;i<100;i++) { float v = get_fp_rand_number(20.0); printf("r is %f\n",v); } return 0;
printf("sizeof double is %d\n",sizeof(double));
printf("sizeof float is %d\n",sizeof(float));
return 0;
pthread_t pth_send;
pthread_t pth_recv;
pthread_create(&pth_send,NULL,send_data,NULL);
pthread_create(&pth_recv,NULL,recv_data,NULL);
pthread_join(pth_send,NULL);
pthread_join(pth_recv,NULL);
return 0;
signal(SIGALRM,on_timer);
set_ticker(1000);
//sleep(8);
struct timeval tv;
tv.tv_sec =10;
tv.tv_usec =0;
fd_set rd;
FD_ZERO(&rd);
FD_SET(0,&rd);
select(1,&rd,NULL,NULL,&tv);
printf("to the end\n");
return 0;
}
//hd_ifp.c============================================================================================== #include<stdio.h> #include<stdlib.h> #include<stdint.h> #include<string.h> #include<fcntl.h> #include<unistd.h> #include<pthread.h> #include<mqueue.h>
#include"hd_ifp_common.h"
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
int counter = 0; int32_t byte_str_2_hex(int8_t* inbuf, int32_t in_size,int8_t* out_buf,int32_t out_size) {
int32_t i=0;
int32_t j=0;
uint8_t err = 0;
while(in_size)
{
if(inbuf[i] == ' ')
{
++i;
--in_size;
}
else
{
if(inbuf[i] >= '0' && inbuf[i] <= '9')
{
out_buf[j] = 16*(inbuf[i] - '0');
}
else if(inbuf[i] >= 'a' && inbuf[i] <= 'f')
{
out_buf[j] = 16*(10 + inbuf[i] - 'a');
}
else if(inbuf[i] >= 'A' && inbuf[i] <= 'F')
{
out_buf[j] = 16*(10 + inbuf[i] - 'A');
}
else
{
err = -1;
break;
}
if(inbuf[i+1] >= '0' && inbuf[i+1] <= '9')
{
out_buf[j] += (inbuf[i+1] - '0');
}
else if(inbuf[i+1] >= 'a' && inbuf[i+1] <= 'f')
{
out_buf[j] += (10 + inbuf[i+1] - 'a');
}
else if(inbuf[i+1] >= 'A' && inbuf[i+1] <= 'F')
{
out_buf[j] += (10 + inbuf[i+1] - 'A');
}
else
{
err = -2;
break;
}
i+=2;
++j;
in_size -= 2;
}
}
if(err < 0)
{
return err;
}
else
{
return j;
}
}
int32_t read_one_line(int fd,int8_t* buffer,int32_t size) { int8_t ch; int32_t i =0; int32_t err = 0; int32_t ret = 0;
while((ret = read(fd,&ch,1)) == 1)
{
if(ch == '\n')
{
break;
}
else
{
buffer[i] = ch;
}
++i;
if(i >= size)
{
err = -1;
break;
}
}
if(err < 0)
{
return err;
}
else
{
if(ret <= 0)
{
printf("xxxxx ret is %d\n",ret);
return ret;
}
else
{
printf("ooooo i is %d\n",i);
return i;
}
}
}
int32_t find_tag(int8_t* buf,int32_t buf_size,int8_t tagh,int8_t tagl) {
int32_t i = 0;
int32_t err = 0;
int8_t result = 0;
while(i < buf_size)
{
if(buf[i] == tagh && buf[i+1] == tagl)
{
result = 1;
break;
}
i++;
}
if(result && i < (buf_size -2))//the last 2 bytes could not be tagh an tagl
{
return i;
}
else
{
err = -1;
return err;
}
}
int32_t find_message(int8_t* buf,int32_t buf_size,int32_t offset) {
int32_t len = buf[offset]*16 + buf[offset+1];
if(len + 2 + offset > buf_size)
{
return -1;
}
else
{
return len;
}
}
int8_t tbuf[8] = {0x1f,0x17,0x34,0xca,0x8a,0x32,0x12,0x34};
void* ifp_read(void* arg) { uint8_t raw_buffer[256] = {0}; uint8_t m_buffer[256] = {0}; int fd;
int offset_i = find_tag(tbuf,8,0x12,0x34);
printf("offset_i is %d\n",offset_i);
return (void*)0;
fd = open("./ifp_t.log",O_RDONLY);
if(fd < 0)
{
perror("open failed\n");
exit(EXIT_FAILURE);
}
//=====================================================
#if 0 off_t isize = lseek(fd,0,SEEK_END); printf("isize is %d\n",isize); lseek(fd,0,SEEK_SET);
if(read(fd,raw_buffer,isize) != isize)
{
perror("read error\n");
exit(EXIT_FAILURE);
}
#endif //=====================================================
int32_t isize;
int32_t tsize;
memset(raw_buffer,0,128);
while((isize = read_one_line(fd,raw_buffer,128)) > 0)
{
printf("it is %s\n",raw_buffer);
printf("isize is %d\n",isize);
tsize = byte_str_2_hex(raw_buffer,isize,m_buffer,128);
printf("tsize is %d\n",tsize);
for(int i=0;i< tsize; i++)
{
printf("byte is %02x\n",m_buffer[i]);
}
memset(raw_buffer,0,128);
memset(m_buffer,0,128);
}
return (void*)0;
while(1)
{
pthread_mutex_lock(&mutex1);
printf("tha counter is %d\n",counter);
if(counter == 10)
{
pthread_mutex_unlock(&mutex1);
//exit(0);
break;
}
else
{
counter++;
pthread_mutex_unlock(&mutex1);
}
}
return 0;
}
void* ifp_write(void* arg) { while(1) { pthread_mutex_lock(&mutex1);
pthread_mutex_unlock(&mutex1);
}
return 0;
}
int main(int argc,char* argv[]) { pthread_t ifpr,ifpw;
pthread_create(&ifpr,NULL,ifp_read,NULL);
// pthread_create(&ifpw,NULL,ifp_write,NULL);
pthread_join(ifpr,NULL);
// pthread_join(ifpw,NULL);
return 0;
}
//=============================================================
#if 0 mqd_t server; struct mq_attr attr;
attr.mq_flags = 0; attr.mq_maxmsg = 128; attr.mq_msgsize = 1024; attr.mq_curmsgs = 0;
printf("1111111111111\n"); if((server = mq_open("/tmq",O_RDONLY|O_CREAT,0660,&attr)) == -1) { perror("server:mq_open failed\n"); exit(EXIT_FAILURE);
}
printf("2222222222222\n"); char out_buffer[32]="hello\n"; mq_send(server,out_buffer,2,0); printf("33333333333333\n"); #endif
//=============================================================
//hd_ifp_common.h================================================================================== #ifndef HD_IFP_COMMOM_H #define HD_IFP_COMMOM_H
#ifdef __cplusplus extern "C" { #endif /* __cplusplus*/
typedef enum {
HD_UART_SUCCESS = 0,
HD_UART_COMM_ERROR,
HD_UART_COMM_TIMEOUT,
HD_UART_UNSUPPORTED_DEVICE,
HD_UART_DEVICE_UNINITIALIZED,
HD_UART_HW_ERROR,
HD_UART_INVALID_PARAM,
HD_UART_PARAM_OUT_OF_RANGE,
HD_UART_INVALID_HANDLE,
HD_UART_IRQ_PENDING,
HD_UART_READ_STATUS_TIMEOUT,
HD_UART_INVALID_POWER_STATE,
HD_UART_HAL_INIT_ERROR,
HD_UART_INSUFFICIENT_FIFO_SPACE,
HD_UART_CRC_ERROR,
HD_UART_QUEUE_FULL,
HD_UART_QUEUE_EMPTY,
HD_UART_BUFFER_TOO_SMALL,
HD_UART_INVALID_PORT,
HD_UART_ADDRESS_FILTER_TABLE_FULL,
HD_UART_COMM_BUSY,
HD_UART_ZERO_LENGTH_TRX,
HD_UART_SW_RESET_TIMEOUT,
HD_UART_NOT_IMPLEMENTED,
HD_UART_NOT_IMPLEMENTED_SOFTWARE,
HD_UART_UNSUPPORTED_FEATURE,
HD_UART_PLACEHOLDER_ERROR,
}hd_uart_result_e;
#ifdef __cplusplus extern "C" { #endif /* __cplusplus*/
#endif
//Makefile==============================================================================================
hd_ifp.exe: hd_ifp.o hd_ifp_common.h gcc -o hd_ifp.exe hd_ifp.o
hd_ifp.o:hd_ifp.c hd_ifp_common.h gcc -c hd_ifp.c
.PHONY: clean clean: rm -rf *.exe *.o
//cal_current_looped_mode_uio.sh=============================================================
#!/bin/bash #like 0x31c1 if [ $# -lt 1 ];then echo "less parameters" exit fi
let a=$1
#res=echo "scale=4;(($a*1000*2.5)/65535)/100"|bc
res=echo "scale=2;(($a*25)/65535)"|bc
echo "Current is $res mA"
//cal-bc.sh================================================================================ #!/bin/bash
a=19 b=3
c=$(echo "scale=4;$a/$b" | bc) echo $c
//calhexarray.sh========================================================================== #!/bin/bash
#like 0x31c1 if [ $# -lt 1 ];then echo "less parameters" exit fi
while read val do val="0x"$val
let tval=$val
echo $tval
res=echo "scale=4;($tval*2100)/(65535-$tval)"|bc
echo "R is $res hom"
done < $1
#let a=$1
#res=echo "scale=4;($a*2100)/(65535-$a)"|bc
#echo "R is $res hom"
//calhexval.sh==============================================================================
#!/bin/bash #like 0x31c1 if [ $# -lt 1 ];then echo "less parameters" exit fi
let a=$1
res=echo "scale=4;($a*2100)/(65535-$a)"|bc
echo "R is $res hom"
//cur_udp_kbd_tim.c==================================================================================
#include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <curses.h> #include <unistd.h> #include <aio.h> #include <signal.h> #include <fcntl.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <netdb.h>
#define PORT 8900 #define MAXLINE 1024
#define LOG_FILE "game.log"
#define DIALOG_WIDTH 40 #define DIALOG_HEIGHT 20 #define CONTENT_WIDTH (DIALOG_WIDTH - 2)
void set_colors() { // these don't actually have anything to do with binary, so we are free to use "normal" numbers init_pair(1, COLOR_RED, COLOR_BLACK); // red on black init_pair(2, COLOR_GREEN, COLOR_BLACK); // green on black init_pair(3, COLOR_YELLOW, COLOR_BLACK); // yellow on black init_pair(4, COLOR_BLUE, COLOR_BLACK); // blue on black init_pair(5, COLOR_MAGENTA, COLOR_BLACK); // magenta on black init_pair(6, COLOR_CYAN, COLOR_BLACK); // cyan on black init_pair(7, COLOR_WHITE, COLOR_BLACK); // white on black }
void end_curses() { endwin(); }
// a simple log function, works similar to printf void glog(const char *format, ... ) { va_list args; // argument list static FILE *logfile = NULL; // file pointer to the logfile char *fformat; // the modified format of the string which will be written to the logfile int length; // length of the format
if(!(format == NULL && logfile == NULL)) { // open the logfile if not already opened if(logfile == NULL) { logfile = fopen(LOG_FILE, "w"); // if that doesn't work exit with an error message if(logfile == NULL) { fprintf(stderr, "Cannot open logfile %s\n", LOG_FILE); exit(EXIT_FAILURE); } }
// if NULL is given as format, close the opened file
if(format != NULL) {
// increase length by 2 (for \n\0
length = strlen(format) + 2;
// allocate memory
fformat = malloc(sizeof(char) * length);
// copy the format over
strncpy(fformat, format, length - 2);
// append \n\0
fformat[length - 2] = '\n';
fformat[length - 1] = '\0';
// get the rest of the arguments
va_start(args, format);
// use vfprintf() to
vfprintf(logfile, fformat, args);
// forces the logmessage to be written into the file right now
fflush(logfile);
va_end(args);
// free the allocated memory for the format string
free(fformat);
}
else
{
// close the logfile
fclose(logfile);
}
} }
// create a basic dialog with title which looks like this: // // +--------------------------------------+ // +---------------- TITLE ---------------+ // +--------------------------------------+ // | | // | | // | | // | | // | | // | | // | | // | | // | | // | | // | | // | | // | | // | | // | | // | | // +--------------------------------------+ // WINDOW *create_dialog_window(const char *title) { WINDOW *win; int sx, sy, i, u, startpos;
// get the screen size getmaxyx(stdscr, sy, sx); // create a little window in the center of the screen with a border and a size of 40x20 win = newwin(DIALOG_HEIGHT, DIALOG_WIDTH, sy / 2 - DIALOG_HEIGHT / 2, sx / 2 - DIALOG_WIDTH / 2);
// create the border wborder(win, '|', '|', '-', '-', '+', '+', '+', '+');
// fill the first two lines with "-" and "+" on the border for(u = 1; u <= 2; u++) { for(i = 0; i < DIALOG_WIDTH; i++) { mvwprintw(win, u, i, "%c", i == 0 || i == DIALOG_WIDTH - 1 ? '+' : '-'); } }
// print the title in the middle of the dialog startpos = DIALOG_WIDTH / 2 - strlen(title) / 2; // print a space before the title mvwprintw(win, 1, startpos - 1, " "); // print the title itself mvwprintw(win, 1, startpos, "%s", title); // print a space after the title mvwprintw(win, 1, startpos + strlen(title), " "); return win; }
// creates a dialog with menu entries, you can press numbers to select a menu entry and close the dialog int create_numbered_dialog(const char *title, const char *contents, int lines) { WINDOW *win = create_dialog_window(title); int i, ch, number = 0;
// insert menu entries into the dialog for(i = 0; i < lines; i++) { mvwprintw(win, i + 3, 1, &contents[i * CONTENT_WIDTH], i + 1); }
// display the dialog wrefresh(win);
// wait for some input while((ch = wgetch(win))) { // error? begin again. //if(ch == ERR) continue;
// select the first menu entry if enter is pressed
if(ch == '\n') ch = '1';
// a number pressed?
if(ch >= '0' && ch <= '9') {
number = ch - '0';
// prevent from handling numbers which are > than the number of menu entries
if(ch - '0' <= lines) {
// get out of the loop
break;
}
}
}
// delete the window delwin(win);
// return the number pressed return number; }
// displays the main menu int display_menu() { // the contents of the menu // %i will be replaced with the number of the menu entry char menu[][CONTENT_WIDTH] = { "%i) Start the game", "%i) Highscores", "%i) Controls", "%i) Help", "%i) Clear Highscores", "%i) Exit" }; // create a numbered dialog return create_numbered_dialog("MENU", (char *)menu, 6); }
void main_menu() { int selected_menu_entry; do { selected_menu_entry = display_menu(); if(selected_menu_entry == 1) { // run the game //run(); } else if(selected_menu_entry == 2) { // display the highscores //show_highscores(); } else if(selected_menu_entry == 3) { // display a dialog which explains the controls of the game //display_controls(); } else if(selected_menu_entry == 4) { // display a dialog which explains the elements of the game //display_help(); } else if(selected_menu_entry == 5) { // clear highscores #if 0 if(clear_score_dialog() == 1) { clear_highscore(); } #endif } // leave if the menu entry "exit" is chosen } while(selected_menu_entry != 6); }
#if 0 void enable_kbd_signals(void) {
int fd_flags;
fcntl(0,F_SETOWN,getpid());
fd_flags = fcntl(0,F_GETFL);
fcntl(0,F_SETFL,(fd_flags|O_ASYNC));
//fcntl(0,F_SETFL,(fd_flags|O_RSYNC));
} #endif
struct aiocb kbcbuf; void setup_aio_buffer(void) {
static char input[1];
kbcbuf.aio_fildes = 0;
kbcbuf.aio_buf = input;
kbcbuf.aio_nbytes = 1;
kbcbuf.aio_offset = 0;
kbcbuf.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
kbcbuf.aio_sigevent.sigev_signo = SIGIO;
}
void on_input(int signum) { #if 0 int c = getch(); move(15,15); addch(c);
#endif
int c;
char *cp = (char*)kbcbuf.aio_buf;/*cast to char*/
if(aio_error(&kbcbuf) != 0)
{
perror("reading failed");
}
else
{
if(aio_return(&kbcbuf) == 1)
{
c=*cp;
move(15,15);
addch(c);
refresh();
if(c == 'q')
{
endwin();
printf("that is it\n");
exit(EXIT_SUCCESS);
}
}
aio_read(&kbcbuf);
}
}
void init_curses() {
#if _BSD_SOURCE || _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600 // by default, ncurses stops the execution of the program for // 1 second if escape is pressed. Disable this behaviour. setenv("ESCDELAY", "0", 1); #endif
initscr(); // get more control over the input cbreak(); // getch() returns ERR if no input is present and doesn't wait //nodelay(stdscr, TRUE); // don't echo the inserted keys to the screen noecho(); // colors! start_color(); set_colors(); // also grab keys like F1 etc. keypad(stdscr, TRUE);
}
int main(int argc, char* argv[])
{
int sockfd;
char hname[128]={0};
char buffer[MAXLINE];
char *hello = "Hello from server";
struct sockaddr_in servaddr, cliaddr;
struct hostent *hent=NULL;
gethostname(hname,sizeof(hname));
hent = gethostbyname(hname);
if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 )
{
perror("socket creation failed");
exit(EXIT_FAILURE);
}
memset(&servaddr, 0, sizeof(servaddr));
memset(&cliaddr, 0, sizeof(cliaddr));
// Filling server information
servaddr.sin_family = AF_INET; // IPv4
//servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(PORT);
//servaddr.sin_port = PORT;
// Bind the socket with the server address
if ( bind(sockfd, (const struct sockaddr *)&servaddr,
sizeof(servaddr)) < 0 )
{
perror("bind failed");
exit(EXIT_FAILURE);
}
int len, n;
len = sizeof(cliaddr); //len is value/resuslt
WINDOW *xw;
void on_input(int);
signal(SIGIO,on_input);
//enable_kbd_signals();
setup_aio_buffer();
aio_read(&kbcbuf);
init_curses();
while(1)
{
//pause();
move(20,25);
//printf("waiting on port %d\n",PORT);
printw("waiting on port %d\n",PORT);
refresh();
#if 0
n = recvfrom(sockfd, (char *)buffer, MAXLINE,
MSG_WAITALL, ( struct sockaddr *) &cliaddr,
&len);
#endif
n = recvfrom(sockfd, (char *)buffer, MAXLINE,
0, ( struct sockaddr *) &cliaddr,
&len);
buffer[n] = '\0';
//printf("Client : %s\n", buffer);
move(25,25);
printw("Client : %s\n", buffer);
refresh();
//sleep(5);
}
// main_menu();
// xw=create_dialog_window("hello");
// wrefresh(xw);
// refresh();
// sleep(4);
end_curses();
}
//cur-out-uio.sh=====================================================================
#!/bin/bash #like 0x31c1 if [ $# -lt 1 ];then echo "less parameters" exit fi
let a=$1
cur=echo "scale=4;($a/65535)*2.5*10"|bc
echo "cur is $cur ma"
//glog.c===============================================================================
#include "glog.h"
// a simple log function, works similar to printf void glog(const char *format, ... ) { va_list args; // argument list static FILE *logfile = NULL; // file pointer to the logfile char *fformat; // the modified format of the string which will be written to the logfile int length; // length of the format
if(!(format == NULL && logfile == NULL)) { // open the logfile if not already opened if(logfile == NULL) { //logfile = fopen(LOG_FILE, "w"); logfile = fopen(LOG_FILE, "a"); // if that doesn't work exit with an error message if(logfile == NULL) { fprintf(stderr, "Cannot open logfile %s\n", LOG_FILE); exit(EXIT_FAILURE); } }
// if NULL is given as format, close the opened file
if(format != NULL) {
// increase length by 2 (for \n\0
length = strlen(format) + 2;
// allocate memory
fformat = malloc(sizeof(char) * length);
// copy the format over
strncpy(fformat, format, length - 2);
// append \n\0
fformat[length - 2] = '\n';
fformat[length - 1] = '\0';
// get the rest of the arguments
va_start(args, format);
// use vfprintf() to
vfprintf(logfile, fformat, args);
// forces the logmessage to be written into the file right now
fflush(logfile);
va_end(args);
// free the allocated memory for the format string
free(fformat);
} else {
// close the logfile
fclose(logfile);
}
} }
int main(int argc, char*argv[]) {
glog("%d\t%s\n",93,"second"); glog("%d\t%s\n",73,"third");
return 0;
}
//glog.h=================================================================================== #ifndef GLOG_H #define GLOG_H
#include <stdio.h> #include <stdarg.h> #include <string.h> #include <stdlib.h> //#include "types.h"
#define LOG_FILE "game.log"
void glog(const char *format, ... );
#endif /* GLOG_H */
//hlog.c============================================================================================
#include <stdio.h> #include <stdarg.h> #include <string.h> #include <stdlib.h> #include <unistd.h>
// a simple log function, works similar to printf void hlog(const char *name,const char *format, ... ) {
va_list args; // argument list static FILE *logfile = NULL; // file pointer to the logfile char *fformat; // the modified format of the string which will be written to the logfile int length; // length of the format
logfile = fopen(name, "a");
// if that doesn't work exit with an error message
if(logfile == NULL)
{
//fprintf(stderr, "Cannot open logfile %s\n", LOG_FILE);
fprintf(stderr, "Cannot open logfile %s\n", name);
exit(EXIT_FAILURE);
}
// increase length by 2 (for \n\0
length = strlen(format) + 2;
// allocate memory
fformat = malloc(sizeof(char) * length);
// copy the format over
strncpy(fformat, format, length - 2);
// append \n\0
fformat[length - 2] = '\n';
fformat[length - 1] = '\0';
// get the rest of the arguments
va_start(args, format);
// use vfprintf() to
vfprintf(logfile, fformat, args);
// forces the logmessage to be written into the file right now
fflush(logfile);
va_end(args);
// free the allocated memory for the format string
free(fformat);
fclose(logfile);
}
int main(int argc, char*argv[]) {
hlog("x.log","%d\t%s\n",93,"second");
hlog("x.log","%d\t%s\n",73,"third");
hlog("y.log","%d\t%s\n",33,"second");
hlog("y.log","%d\t%s\n",43,"third");
return 0;
}
//io_test.c============================================================================================== #include<stdio.h> #include<stdlib.h> #include<string.h> #include<sys/types.h> #include<sys/stat.h> #include<sys/time.h> #include<unistd.h> #include<pthread.h> #include<sys/select.h>
typedef struct plant_pot {
uint32_t version;
float env_temperature;
float env_moisture;
float soil_temperature;
float soil_moisture;
}PLANT_POT_t;
#define NUM_PLANT_POT 8 PLANT_POT_t pp[NUM_PLANT_POT] = {0};
void on_timer(int signum) { static int c =0; if(signum == SIGALRM) { printf("on timer %d\n",c++); } }
int set_ticker(int msec) { struct itimerval new_timerset; long sec,usec;
sec = msec/1000;
usec = (msec%1000)*1000L;
new_timerset.it_interval.tv_sec = sec;
new_timerset.it_interval.tv_usec = usec;
new_timerset.it_value.tv_sec = sec;
new_timerset.it_value.tv_usec = usec;
return setitimer(ITIMER_REAL,&new_timerset,NULL);
}
int32_t get_sec_val(char*s) { int32_t val = -1; if(s == NULL) { return -1; }
if(strlen(s) >= 25)
{
if(s[17] >= 0x30 && s[17] <= 0x39 && s[18] >= 0x30 && s[18] <= 0x39 )
{
val = (s[17]-0x30)*10 + (s[18] - 0x30);
}
}
return -1;
}
void* send_data(void* arg) { while(1) {
time_t t = time(NULL);
char* s = ctime(&t);
int32_t val = get_sec_val(s);
printf("sec is %d\n",val);
printf("s len is %d\n",strlen(s));
printf("send data\n");
printf("time is %s\n",s);
sleep(1);
}
}
void* recv_data(void* arg) { while(1) { printf("recv data\n"); sleep(1);
}
}
float get_fp_rand_number(float n) {
return ((float)rand()/(float)(RAND_MAX)*n);
}
void* read_plant_pot_data(void* arg) {
int i =0;
while(1)
{
for(i=0; i< NUM_PLANT_POT; i++)
{
pp[i].version = 1;
pp[i].env_temperature = 25.8;
pp[i].env_moisture = 54.2;
pp[i].soil_temperature = 25.9;
pp[i].soil_moisture = 65.6;
}
sleep(10);
}
}
int main(int argc, char* argv[]) { for(int i=0;i<100;i++) { float v = get_fp_rand_number(20.0); printf("r is %f\n",v); } return 0;
printf("sizeof double is %d\n",sizeof(double));
printf("sizeof float is %d\n",sizeof(float));
return 0;
pthread_t pth_send;
pthread_t pth_recv;
pthread_create(&pth_send,NULL,send_data,NULL);
pthread_create(&pth_recv,NULL,recv_data,NULL);
pthread_join(pth_send,NULL);
pthread_join(pth_recv,NULL);
return 0;
signal(SIGALRM,on_timer);
set_ticker(1000);
//sleep(8);
struct timeval tv;
tv.tv_sec =10;
tv.tv_usec =0;
fd_set rd;
FD_ZERO(&rd);
FD_SET(0,&rd);
select(1,&rd,NULL,NULL,&tv);
printf("to the end\n");
return 0;
}
//llist.c==================================================================================================== #include<stdio.h> #include<stdlib.h> #include<string.h> #include<time.h> #include<sys/types.h> #include<sys/stat.h> #include<unistd.h>
typedef struct tnode { uint32_t num; struct tnode *next;
}TNODE,*pTNODE;
pTNODE insert_tnode(pTNODE root,uint32_t n) {
pTNODE node=(pTNODE)malloc(sizeof(TNODE));
if(node == NULL)
{
perror("malloc failed!\n");
exit(EXIT_FAILURE);
}
node->num = n;
if(root == NULL)
{
node->next = NULL;
root = node;
}
else
{
node->next = root;
root = node;
}
return root;
}
pTNODE delete_tnode(pTNODE root,uint32_t n) { pTNODE prev = NULL; pTNODE cur = root;
pTNODE temp = NULL;
while(cur && cur->num != n )
{
prev = cur;
cur = cur->next;
}
if(cur == NULL)
{
return root;
}
if(prev == NULL)
{
temp = cur;
root = root->next;
}
else if(cur->next == NULL)
{
temp = cur;
prev->next = NULL;
}
else
{
temp = cur;
prev->next = cur->next;
}
free(temp);
return root;
}
uint32_t tllist(pTNODE root) {
while(root)
{
printf("%d\n",root->num);
root = root->next;
}
return 0;
}
int main(int argc,char* argv[]) {
pTNODE root = NULL;
for(int m=0;m<8;m++)
{
root = insert_tnode(root,m+1);
}
printf("========================\n");
tllist(root);
printf("========================\n");
root = delete_tnode(root,5);
tllist(root);
printf("========================\n");
root = delete_tnode(root,9);
tllist(root);
printf("========================\n");
root = delete_tnode(root,1);
tllist(root);
printf("========================\n");
root = delete_tnode(root,10);
tllist(root);
return 0;
}
//loopq.c=============================================================================================
#include <stdio.h> #include <stdlib.h> #include <time.h>
typedef struct _queue { uint32_t head; uint32_t tail; uint32_t* buf;
}Queue;
#define qSize 8 Queue qa; uint32_t myBuffer[qSize+1]={0};
int32_t initQueue(Queue *q,uint32_t *buffer) { q->head =0; q->tail = q->head; q->buf=buffer;
return 0;
}
int32_t enQueue(Queue*q,uint32_t n) { if((q->tail +1)%(qSize+1) == q->head) { printf("The queue has been full!\n"); return -1;
}
q->buf[q->tail] = n;
q->tail = (q->tail +1)%(qSize+1);
return 0;
}
int32_t deQueue(Queue*q,uint32_t *val) { if(q->tail == q->head) { printf("The Queue has been empty\n"); return -1; }
*val = q->buf[q->head];
q->head= (q->head +1)%(qSize+1);
return 0;
}
int32_t compareArray(uint32_t *sArray,uint32_t *dArray,uint32_t len) {
uint32_t i;
for(i=0;i<len;i++)
{
if(sArray[i] != dArray[i])
{
return -1;
}
}
return 1;
}
uint32_t enlist[qSize]={0}; uint32_t delist[qSize]={0};
int main(int argc ,char*argv[]) { int32_t rv=0; int32_t i=0;
srand(time(NULL));
uint32_t vlist[16]={0};
initQueue(&qa,myBuffer);
for(i=0;i<qSize;i++)
{
vlist[i] = rand()%0xffff;
}
for(i=0;i<qSize;i++)
{
enQueue(&qa,enlist[i]);
}
for(i=0;i<qSize;i++)
{
deQueue(&qa,&delist[i]);
}
if(compareArray(enlist,delist,qSize) ==1)
{
printf("success\n");
return 0;
}
else
{
printf("error\n");
return -1;
}
return 0;
}
//mcrypt-test.c===============================================================================================
#include <stdio.h> #include <stdlib.h> #include <string.h>
/*
- MCrypt API available online:
- http://linux.die.net/man/3/mcrypt */ #include <mcrypt.h>
#include <math.h> #include <stdint.h> #include <stdlib.h>
int encrypt( void* buffer, int buffer_len, /* Because the plaintext could include null bytes*/ char* IV, char* key, int key_len ){ MCRYPT td = mcrypt_module_open("rijndael-128", NULL, "cbc", NULL); //MCRYPT td = mcrypt_module_open("rijndael-128", NULL, "ecb", NULL); int blocksize = mcrypt_enc_get_block_size(td); if( buffer_len % blocksize != 0 ){return 1;}
mcrypt_generic_init(td, key, key_len, IV);
mcrypt_generic(td, buffer, buffer_len);
mcrypt_generic_deinit (td);
mcrypt_module_close(td);
return 0;
}
int decrypt( void* buffer, int buffer_len, char* IV, char* key, int key_len ){ MCRYPT td = mcrypt_module_open("rijndael-128", NULL, "cbc", NULL); int blocksize = mcrypt_enc_get_block_size(td); if( buffer_len % blocksize != 0 ){return 1;}
mcrypt_generic_init(td, key, key_len, IV);
mdecrypt_generic(td, buffer, buffer_len);
mcrypt_generic_deinit (td);
mcrypt_module_close(td);
return 0;
}
void display(char* ciphertext, int len){ int v; for (v=0; v<len; v++){ //printf("%d ", ciphertext[v]); printf("%#02x ", ciphertext[v]); } printf("\n"); }
uint8_t keyAes128[] = {0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c};
uint8_t plainAes128[] = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a};
uint8_t cipherAes128[] = {0x3a, 0xd7, 0x7b, 0xb4, 0x0d, 0x7a, 0x36, 0x60, 0xa8, 0x9e, 0xca, 0xf3, 0x24, 0x66, 0xef, 0x97};
uint8_t ive[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
int mencrypt( void* buffer, int buffer_len, /* Because the plaintext could include null bytes*/ char* IV, char* key, int key_len ){ MCRYPT td = mcrypt_module_open("rijndael-128", NULL, "ecb", NULL); int blocksize = mcrypt_enc_get_block_size(td); if( buffer_len % blocksize != 0 ){return 1;}
mcrypt_generic_init(td, key, key_len, NULL);
mcrypt_generic(td, buffer, buffer_len);
mcrypt_generic_deinit (td);
mcrypt_module_close(td);
return 0;
}
int main() { MCRYPT td, td2; char * plaintext = "test text 123"; char* IV = "AAAAAAAAAAAAAAAA"; char key = "0123456789abcdef"; int keysize = 16; / 128 bits / char buffer; int buffer_len = 16;
buffer = calloc(1, buffer_len);
//strncpy(buffer, plaintext, buffer_len);
strncpy(buffer, plainAes128, buffer_len);
printf("==C==\n");
//printf("plain: %s\n", plaintext);
// encrypt(buffer, buffer_len, IV, key, keysize); encrypt(buffer, buffer_len, ive, keyAes128, keysize); //mencrypt(buffer, buffer_len, NULL, keyAes128, keysize);
printf("cipher: "); display(buffer , buffer_len);
//decrypt(buffer, buffer_len, IV, key, keysize);
//printf("decrypt: %s\n", buffer);
return 0;
}
//mvf.sh============================================================================================= #!/bin/bash
for e in ls *.txt *.log
do
mv $e sub_$e echo $e
done
echo "done"
//mylog.c=======================================================================================
#include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <string.h>
#define LOG_FILE "udat.log"
// a simple log function, works similar to printf void glog(const char *format, ... ) { va_list args; // argument list static FILE *logfile = NULL; // file pointer to the logfile char *fformat; // the modified format of the string which will be written to the logfile int length; // length of the format
if(!(format == NULL && logfile == NULL)) { // open the logfile if not already opened if(logfile == NULL) { //logfile = fopen(LOG_FILE, "w"); logfile = fopen(LOG_FILE, "a"); // if that doesn't work exit with an error message if(logfile == NULL) { fprintf(stderr, "Cannot open logfile %s\n", LOG_FILE); exit(EXIT_FAILURE); } }
// if NULL is given as format, close the opened file
if(format != NULL) {
// increase length by 2 (for \n\0
length = strlen(format) + 2;
// allocate memory
fformat = malloc(sizeof(char) * length);
// copy the format over
strncpy(fformat, format, length - 2);
// append \n\0
fformat[length - 2] = '\n';
fformat[length - 1] = '\0';
// get the rest of the arguments
va_start(args, format);
// use vfprintf() to
vfprintf(logfile, fformat, args);
// forces the logmessage to be written into the file right now
fflush(logfile);
va_end(args);
// free the allocated memory for the format string
free(fformat);
} else {
// close the logfile
fclose(logfile);
}
} }
int main(int argc, char*argv[]) {
glog("%d\t%s\n",93,"second");
glog("%d\t%s\n",73,"third");
glog("%s\t%s\n","string-A","string-B");
glog("%s\t%f\n","string-C",3.1415);
printf("done\r\n");
return 0;
}
//myudp-dat-processing.c===================================================================================================
#include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <time.h> #include <string.h> //#include <curses.h> #include <unistd.h> #include <aio.h> #include <signal.h> #include <fcntl.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <netdb.h>
#define PORT 0xBAC0 #define MAXLINE 1500
#define LOG_FILE "bacnet0.log"
#define DIALOG_WIDTH 40 #define DIALOG_HEIGHT 20 #define CONTENT_WIDTH (DIALOG_WIDTH - 2)
// a simple log function, works similar to printf void bacnet0_log(const char *format, ... ) { va_list args; // argument list static FILE *logfile = NULL; // file pointer to the logfile char *fformat; // the modified format of the string which will be written to the logfile int length; // length of the format
if(!(format == NULL && logfile == NULL)) {
// open the logfile if not already opened
if(logfile == NULL) {
logfile = fopen(LOG_FILE, "w");
// if that doesn't work exit with an error message
if(logfile == NULL) {
fprintf(stderr, "Cannot open logfile %s\n", LOG_FILE);
exit(EXIT_FAILURE);
}
}
// if NULL is given as format, close the opened file
if(format != NULL) {
// increase length by 2 (for \n\0
length = strlen(format) + 2;
// allocate memory
fformat = malloc(sizeof(char) * length);
// copy the format over
strncpy(fformat, format, length - 2);
// append \n\0
//fformat[length - 2] = '\n';
fformat[length - 2] = '\0';
fformat[length - 1] = '\0';
// get the rest of the arguments
va_start(args, format);
// use vfprintf() to
vfprintf(logfile, fformat, args);
// forces the logmessage to be written into the file right now
fflush(logfile);
va_end(args);
// free the allocated memory for the format string
free(fformat);
}
else
{
// close the logfile
fclose(logfile);
}
}
}
int val=0; char mystr[1024]={0}; int main(int argc, char* argv[]) {
#if 1 if(setvbuf(stdin,NULL,_IOLBF,0) != 0) { perror("setvbuf failed\n"); } #endif
while(1)
{
scanf("%s %d",mystr,&val);
//fgets(mystr,strlen(mystr),stdin);
//read(STDIN_FILENO,mystr,sizeof(mystr));
if(strcmp(mystr,"quit") == 0)
{
bacnet0_log("%s\n",mystr);
exit(EXIT_SUCCESS);
}
//fgets(mystr,sizeof(mystr),stdin);
//read(STDIN_FILENO,mystr,sizeof(mystr));
// printf("%s %d",mystr,val+1);
bacnet0_log("%s\n",mystr);
memset(mystr,0,sizeof(mystr));
}
}
//myudp-rx.c================================================================================================= #include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <time.h> #include <string.h> //#include <curses.h> #include <unistd.h> #include <aio.h> #include <signal.h> #include <fcntl.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <netdb.h>
#define PORT 0xBAC0 #define MAXLINE 1500
#define LOG_FILE "bacnet0.log"
#define DIALOG_WIDTH 40 #define DIALOG_HEIGHT 20 #define CONTENT_WIDTH (DIALOG_WIDTH - 2)
uint8_t bqr_whois[]={ 0x81,0x0a,0x00,0x0c,0x01,0x20, 0xff,0xff,0x00,0xff,0x10,0x08
};
uint8_t brp_im[]={ 0x81,0x0b,0x00,0x19,0x01,0x20,0xff,0xff,0x00,0xff,0x10,0x00,0xc4,0x02,0x00,0x03, 0xf1,0x22,0x04,0x00,0x91,0x03,0x22,0x01,0x04 };
extern int32_t make_internet_address(int8_t * hostname,int32_t port,struct sockaddr_in *addrp);
int sockfd; char hname[128]={0}; uint8_t buffer[MAXLINE]; char *hello = "Hello from server"; struct sockaddr_in servaddr, cliaddr; struct hostent *hent=NULL;
// a simple log function, works similar to printf void bacnet0_log(const char *format, ... ) { va_list args; // argument list static FILE *logfile = NULL; // file pointer to the logfile char *fformat; // the modified format of the string which will be written to the logfile int length; // length of the format
if(!(format == NULL && logfile == NULL)) {
// open the logfile if not already opened
if(logfile == NULL) {
logfile = fopen(LOG_FILE, "w");
// if that doesn't work exit with an error message
if(logfile == NULL) {
fprintf(stderr, "Cannot open logfile %s\n", LOG_FILE);
exit(EXIT_FAILURE);
}
}
// if NULL is given as format, close the opened file
if(format != NULL) {
// increase length by 2 (for \n\0
length = strlen(format) + 2;
// allocate memory
fformat = malloc(sizeof(char) * length);
// copy the format over
strncpy(fformat, format, length - 2);
// append \n\0
//fformat[length - 2] = '\n';
fformat[length - 2] = '\0';
fformat[length - 1] = '\0';
// get the rest of the arguments
va_start(args, format);
// use vfprintf() to
vfprintf(logfile, fformat, args);
// forces the logmessage to be written into the file right now
fflush(logfile);
va_end(args);
// free the allocated memory for the format string
free(fformat);
}
else
{
// close the logfile
fclose(logfile);
}
}
}
#if defined(UBUNTU) void enable_kbd_signals(void) {
int fd_flags;
fcntl(0,F_SETOWN,getpid());
fd_flags = fcntl(0,F_GETFL);
fcntl(0,F_SETFL,(fd_flags|O_ASYNC));
//fcntl(0,F_SETFL,(fd_flags|O_RSYNC));
} #endif
#if 0 struct aiocb kbcbuf; void setup_aio_buffer(void) {
static char input[1];
kbcbuf.aio_fildes = 0;
kbcbuf.aio_buf = input;
kbcbuf.aio_nbytes = 1;
kbcbuf.aio_offset = 0;
kbcbuf.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
kbcbuf.aio_sigevent.sigev_signo = SIGIO;
} #endif
int8_t cmd_str[1024];
#if defined(UBUNTU) void on_input(int signum) {
fgets(cmd_str,128,stdin);
printf("cmd_str is %s\n",cmd_str);
if(strcmp(cmd_str,"quit\n") == 0)
{
exit(EXIT_SUCCESS);
}
if(strcmp(cmd_str,"whois\n") ==0)
{
make_internet_address("192.168.0.255",PORT,&cliaddr);
if(sendto(sockfd,bqr_whois,sizeof(bqr_whois),0,(struct sockaddr*)&cliaddr,sizeof(cliaddr)) == -1)
{
perror("udp send failed\n");
exit(EXIT_FAILURE);
}
}
memset(cmd_str,0,sizeof(cmd_str));
}
#endif
#if 0 void on_input(int signum) {
int c;
char *cp = (char*)kbcbuf.aio_buf;/*cast to char*/
if(aio_error(&kbcbuf) != 0)
{
perror("reading failed");
}
else
{
if(aio_return(&kbcbuf) == 1)
{
c=*cp;
if(c == 'q')
{
printf("that is it\n");
exit(EXIT_SUCCESS);
}
}
aio_read(&kbcbuf);
}
} #endif
int32_t make_internet_address(int8_t * hostname,int32_t port,struct sockaddr_in *addrp) {
struct hostent *hp;
bzero((void*)addrp,sizeof(struct sockaddr_in));
hp = gethostbyname(hostname);
if(hp == NULL)
return -1;
bcopy((void*)hp->h_addr,(void*)&addrp->sin_addr,hp->h_length);
addrp->sin_port = htons(port);
addrp->sin_family= AF_INET;
return 0;
}
int main(int argc, char* argv[])
{
#if 0
int sockfd;
char hname[128]={0};
uint8_t buffer[MAXLINE];
char *hello = "Hello from server";
struct sockaddr_in servaddr, cliaddr;
struct hostent *hent=NULL;
#endif
gethostname(hname,sizeof(hname));
hent = gethostbyname(hname);
if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 )
{
perror("socket creation failed");
exit(EXIT_FAILURE);
}
int optval =1;
setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST|SO_REUSEADDR,&optval,sizeof(int));
struct timeval timeout;
timeout.tv_sec = 6;
timeout.tv_usec = 0;
setsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,&timeout,sizeof(timeout));
memset(&servaddr, 0, sizeof(servaddr));
memset(&cliaddr, 0, sizeof(cliaddr));
// Filling server information
servaddr.sin_family = AF_INET; // IPv4
//servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(PORT);
//servaddr.sin_port = PORT;
// Bind the socket with the server address
if ( bind(sockfd, (const struct sockaddr *)&servaddr,sizeof(servaddr)) < 0 )
{
perror("bind failed");
exit(EXIT_FAILURE);
}
int len, n;
len = sizeof(cliaddr); //len is value/resuslt
#if defined(UBUNTU) void on_input(int); signal(SIGIO,on_input); enable_kbd_signals(); #endif // setup_aio_buffer(); // aio_read(&kbcbuf);
memset(buffer,0,sizeof(buffer));
#if 0 //make_internet_address("192.168.0.104",PORT,&cliaddr); make_internet_address("192.168.0.255",PORT,&cliaddr); if(sendto(sockfd,bqr_whois,sizeof(bqr_whois),0,(struct sockaddr*)&cliaddr,sizeof(cliaddr)) == -1) { perror("udp send failed\n"); exit(EXIT_FAILURE);
}
#endif
#if 0 if(argc > 1) {
printf("argc is %d\n",argc);
if(strcmp(argv[1],"whois") == 0)
{
make_internet_address("192.168.0.255",PORT,&cliaddr);
if(sendto(sockfd,bqr_whois,sizeof(bqr_whois),0,(struct sockaddr*)&cliaddr,sizeof(cliaddr)) == -1)
{
perror("udp send failed\n");
}
}
}
#endif
int fpid;
fpid = fork();
if(fpid == -1)
{
perror("fork failed\n");
exit(EXIT_FAILURE);
}
else if(fpid == 0)
{
//execl("./myudp-tx",0);
execl("./myudp-tx","myudp-tx",(char*)0);
}
int pfd[2] = {0};
if(pipe(pfd) == -1)
{
perror("pipe failed\n");
}
fpid = fork();
if(fpid == -1)
{
perror("fork failed\n");
exit(EXIT_FAILURE);
}
else if(fpid == 0)
{
if(dup2(pfd[0],STDIN_FILENO) != STDIN_FILENO)
{
perror("dup2 stdin failed\n");
}
close(pfd[1]);
//execl("./myudp-tx",0);
execl("./myudp-dat-processing","myudp-dat-processing",(char*)0);
}
if(dup2(pfd[1],STDOUT_FILENO) != STDOUT_FILENO)
{
perror("dup2 stdout failed\n");
}
close(pfd[0]);
while(1)
{
//pause();
#if 1 // printf("waiting on port %d\n",PORT); n = recvfrom(sockfd, (char *)buffer, MAXLINE, 0, ( struct sockaddr *) &cliaddr, &len); // printf("recvfrom timeout\n"); // printf("buffer is %s\n",buffer);
//buffer[n] = '\0';
// printf("Client : %s\n", buffer);
//printf("buffer is %s\n",buffer);
if(buffer[12]== 0xc4 && buffer[13] == 0x02)
{
// printf("I am %d\n",1009);
//printf("I am %d\n",(uint32_t)(buffer[14]<<16|buffer[15]<<8|buffer[16]));
// printf("%s %d\n","hello",23);
//printf("%s\r\n","hello");
//write(pfd[1],ts,strlen(ts));
#if 0 time_t it; time(&it); int8_t * tstr = ctime(&it); tstr[strlen(tstr)-1]='\0'; bacnet0_log("%s\n",tstr); //bacnet0_log("I am %d\n",1009); bacnet0_log("I am %d\n",(uint32_t)(buffer[14]<<16|buffer[15]<<8|buffer[16])); //time(&it); //bacnet0_log("%s\tI am %d\n",(uint32_t)(buffer[14]<<16|buffer[15]<<8|buffer[16]),ctime(&it)); #endif
}
#endif
#if 0
//if(buffer[5] == 0x20)
if(strcmp(buffer,"whois\n") == 0)
{
//printf("I am: %d\n",1009);
//printf("%s %d\n","world",88);
//puts("world");
write(pfd[1],ts,strlen(ts));
}
#endif
//if(sendto(sockfd,buffer,strlen(buffer),0,(struct sockaddr*)&cliaddr,sizeof(cliaddr)) == -1)
//if(sendto(sockfd,brp_im,sizeof(brp_im),0,(struct sockaddr*)&cliaddr,sizeof(cliaddr)) == -1)
#if 0 if(strcmp(buffer,"whois\n") == 0) { printf("whois\n"); make_internet_address("192.168.0.255",PORT,&cliaddr); if(sendto(sockfd,bqr_whois,sizeof(bqr_whois),0,(struct sockaddr*)&cliaddr,sizeof(cliaddr)) == -1) { perror("udp send failed\n"); exit(EXIT_FAILURE); }
}
#endif
char *ts="hello";
if(strcmp(buffer,"hello UDP\n") == 0)
{
//printf("good-bye\n");
printf("%s %d\n","hellox",12);
//puts("quit");
//write(pfd[1],ts,strlen(ts));
}
char *qt="quit";
if(strcmp(buffer,"tx-quit\n") == 0)
{
//printf("good-bye\n");
printf("%s %d\n","quit",12);
//puts("quit");
//write(pfd[1],qt,strlen(qt));
close(pfd[1]);
exit(EXIT_SUCCESS);
}
memset(buffer,0,sizeof(buffer));
// sleep(1);
}
}
//myudp-rx.c============================================================================================================== #include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <time.h> #include <string.h> //#include <curses.h> #include <unistd.h> #include <aio.h> #include <signal.h> #include <fcntl.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <netdb.h>
#define PORT 0xBAC0 #define MAXLINE 1500
#define LOG_FILE "bacnet0.log"
#define DIALOG_WIDTH 40 #define DIALOG_HEIGHT 20 #define CONTENT_WIDTH (DIALOG_WIDTH - 2)
uint8_t bqr_whois[]={ 0x81,0x0a,0x00,0x0c,0x01,0x20, 0xff,0xff,0x00,0xff,0x10,0x08
};
uint8_t brp_im[]={ 0x81,0x0b,0x00,0x19,0x01,0x20,0xff,0xff,0x00,0xff,0x10,0x00,0xc4,0x02,0x00,0x03, 0xf1,0x22,0x04,0x00,0x91,0x03,0x22,0x01,0x04 };
extern int32_t make_internet_address(int8_t * hostname,int32_t port,struct sockaddr_in *addrp);
int sockfd; char hname[128]={0}; uint8_t buffer[MAXLINE]; char *hello = "Hello from server"; struct sockaddr_in servaddr, cliaddr; struct hostent *hent=NULL;
// a simple log function, works similar to printf void bacnet0_log(const char *format, ... ) { va_list args; // argument list static FILE *logfile = NULL; // file pointer to the logfile char *fformat; // the modified format of the string which will be written to the logfile int length; // length of the format
if(!(format == NULL && logfile == NULL)) {
// open the logfile if not already opened
if(logfile == NULL) {
logfile = fopen(LOG_FILE, "w");
// if that doesn't work exit with an error message
if(logfile == NULL) {
fprintf(stderr, "Cannot open logfile %s\n", LOG_FILE);
exit(EXIT_FAILURE);
}
}
// if NULL is given as format, close the opened file
if(format != NULL) {
// increase length by 2 (for \n\0
length = strlen(format) + 2;
// allocate memory
fformat = malloc(sizeof(char) * length);
// copy the format over
strncpy(fformat, format, length - 2);
// append \n\0
//fformat[length - 2] = '\n';
fformat[length - 2] = '\0';
fformat[length - 1] = '\0';
// get the rest of the arguments
va_start(args, format);
// use vfprintf() to
vfprintf(logfile, fformat, args);
// forces the logmessage to be written into the file right now
fflush(logfile);
va_end(args);
// free the allocated memory for the format string
free(fformat);
}
else
{
// close the logfile
fclose(logfile);
}
}
}
#if defined(UBUNTU) void enable_kbd_signals(void) {
int fd_flags;
fcntl(0,F_SETOWN,getpid());
fd_flags = fcntl(0,F_GETFL);
fcntl(0,F_SETFL,(fd_flags|O_ASYNC));
//fcntl(0,F_SETFL,(fd_flags|O_RSYNC));
} #endif
#if 0 struct aiocb kbcbuf; void setup_aio_buffer(void) {
static char input[1];
kbcbuf.aio_fildes = 0;
kbcbuf.aio_buf = input;
kbcbuf.aio_nbytes = 1;
kbcbuf.aio_offset = 0;
kbcbuf.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
kbcbuf.aio_sigevent.sigev_signo = SIGIO;
} #endif
int8_t cmd_str[1024];
#if defined(UBUNTU) void on_input(int signum) {
fgets(cmd_str,128,stdin);
printf("cmd_str is %s\n",cmd_str);
if(strcmp(cmd_str,"quit\n") == 0)
{
exit(EXIT_SUCCESS);
}
if(strcmp(cmd_str,"whois\n") ==0)
{
make_internet_address("192.168.0.255",PORT,&cliaddr);
if(sendto(sockfd,bqr_whois,sizeof(bqr_whois),0,(struct sockaddr*)&cliaddr,sizeof(cliaddr)) == -1)
{
perror("udp send failed\n");
exit(EXIT_FAILURE);
}
}
memset(cmd_str,0,sizeof(cmd_str));
}
#endif
#if 0 void on_input(int signum) {
int c;
char *cp = (char*)kbcbuf.aio_buf;/*cast to char*/
if(aio_error(&kbcbuf) != 0)
{
perror("reading failed");
}
else
{
if(aio_return(&kbcbuf) == 1)
{
c=*cp;
if(c == 'q')
{
printf("that is it\n");
exit(EXIT_SUCCESS);
}
}
aio_read(&kbcbuf);
}
} #endif
int32_t make_internet_address(int8_t * hostname,int32_t port,struct sockaddr_in *addrp) {
struct hostent *hp;
bzero((void*)addrp,sizeof(struct sockaddr_in));
hp = gethostbyname(hostname);
if(hp == NULL)
return -1;
bcopy((void*)hp->h_addr,(void*)&addrp->sin_addr,hp->h_length);
addrp->sin_port = htons(port);
addrp->sin_family= AF_INET;
return 0;
}
int main(int argc, char* argv[])
{
#if 0
int sockfd;
char hname[128]={0};
uint8_t buffer[MAXLINE];
char *hello = "Hello from server";
struct sockaddr_in servaddr, cliaddr;
struct hostent *hent=NULL;
#endif
gethostname(hname,sizeof(hname));
hent = gethostbyname(hname);
if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 )
{
perror("socket creation failed");
exit(EXIT_FAILURE);
}
int optval =1;
setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST|SO_REUSEADDR,&optval,sizeof(int));
struct timeval timeout;
timeout.tv_sec = 6;
timeout.tv_usec = 0;
setsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,&timeout,sizeof(timeout));
memset(&servaddr, 0, sizeof(servaddr));
memset(&cliaddr, 0, sizeof(cliaddr));
// Filling server information
servaddr.sin_family = AF_INET; // IPv4
//servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(PORT);
//servaddr.sin_port = PORT;
// Bind the socket with the server address
if ( bind(sockfd, (const struct sockaddr *)&servaddr,sizeof(servaddr)) < 0 )
{
perror("bind failed");
exit(EXIT_FAILURE);
}
int len, n;
len = sizeof(cliaddr); //len is value/resuslt
#if defined(UBUNTU) void on_input(int); signal(SIGIO,on_input); enable_kbd_signals(); #endif // setup_aio_buffer(); // aio_read(&kbcbuf);
memset(buffer,0,sizeof(buffer));
#if 0 //make_internet_address("192.168.0.104",PORT,&cliaddr); make_internet_address("192.168.0.255",PORT,&cliaddr); if(sendto(sockfd,bqr_whois,sizeof(bqr_whois),0,(struct sockaddr*)&cliaddr,sizeof(cliaddr)) == -1) { perror("udp send failed\n"); exit(EXIT_FAILURE);
}
#endif
#if 0 if(argc > 1) {
printf("argc is %d\n",argc);
if(strcmp(argv[1],"whois") == 0)
{
make_internet_address("192.168.0.255",PORT,&cliaddr);
if(sendto(sockfd,bqr_whois,sizeof(bqr_whois),0,(struct sockaddr*)&cliaddr,sizeof(cliaddr)) == -1)
{
perror("udp send failed\n");
}
}
}
#endif
int fpid;
fpid = fork();
if(fpid == -1)
{
perror("fork failed\n");
exit(EXIT_FAILURE);
}
else if(fpid == 0)
{
//execl("./myudp-tx",0);
execl("./myudp-tx","myudp-tx",(char*)0);
}
int pfd[2] = {0};
if(pipe(pfd) == -1)
{
perror("pipe failed\n");
}
fpid = fork();
if(fpid == -1)
{
perror("fork failed\n");
exit(EXIT_FAILURE);
}
else if(fpid == 0)
{
if(dup2(pfd[0],STDIN_FILENO) != STDIN_FILENO)
{
perror("dup2 stdin failed\n");
}
close(pfd[1]);
//execl("./myudp-tx",0);
execl("./myudp-dat-processing","myudp-dat-processing",(char*)0);
}
if(dup2(pfd[1],STDOUT_FILENO) != STDOUT_FILENO)
{
perror("dup2 stdout failed\n");
}
close(pfd[0]);
while(1)
{
//pause();
#if 1 // printf("waiting on port %d\n",PORT); n = recvfrom(sockfd, (char *)buffer, MAXLINE, 0, ( struct sockaddr *) &cliaddr, &len); // printf("recvfrom timeout\n"); // printf("buffer is %s\n",buffer);
//buffer[n] = '\0';
// printf("Client : %s\n", buffer);
//printf("buffer is %s\n",buffer);
if(buffer[12]== 0xc4 && buffer[13] == 0x02)
{
// printf("I am %d\n",1009);
//printf("I am %d\n",(uint32_t)(buffer[14]<<16|buffer[15]<<8|buffer[16]));
// printf("%s %d\n","hello",23);
//printf("%s\r\n","hello");
//write(pfd[1],ts,strlen(ts));
#if 0 time_t it; time(&it); int8_t * tstr = ctime(&it); tstr[strlen(tstr)-1]='\0'; bacnet0_log("%s\n",tstr); //bacnet0_log("I am %d\n",1009); bacnet0_log("I am %d\n",(uint32_t)(buffer[14]<<16|buffer[15]<<8|buffer[16])); //time(&it); //bacnet0_log("%s\tI am %d\n",(uint32_t)(buffer[14]<<16|buffer[15]<<8|buffer[16]),ctime(&it)); #endif
}
#endif
#if 0
//if(buffer[5] == 0x20)
if(strcmp(buffer,"whois\n") == 0)
{
//printf("I am: %d\n",1009);
//printf("%s %d\n","world",88);
//puts("world");
write(pfd[1],ts,strlen(ts));
}
#endif
//if(sendto(sockfd,buffer,strlen(buffer),0,(struct sockaddr*)&cliaddr,sizeof(cliaddr)) == -1)
//if(sendto(sockfd,brp_im,sizeof(brp_im),0,(struct sockaddr*)&cliaddr,sizeof(cliaddr)) == -1)
#if 0 if(strcmp(buffer,"whois\n") == 0) { printf("whois\n"); make_internet_address("192.168.0.255",PORT,&cliaddr); if(sendto(sockfd,bqr_whois,sizeof(bqr_whois),0,(struct sockaddr*)&cliaddr,sizeof(cliaddr)) == -1) { perror("udp send failed\n"); exit(EXIT_FAILURE); }
}
#endif
char *ts="hello";
if(strcmp(buffer,"hello UDP\n") == 0)
{
//printf("good-bye\n");
printf("%s %d\n","hellox",12);
//puts("quit");
//write(pfd[1],ts,strlen(ts));
}
char *qt="quit";
if(strcmp(buffer,"tx-quit\n") == 0)
{
//printf("good-bye\n");
printf("%s %d\n","quit",12);
//puts("quit");
//write(pfd[1],qt,strlen(qt));
close(pfd[1]);
exit(EXIT_SUCCESS);
}
memset(buffer,0,sizeof(buffer));
// sleep(1);
}
}
//myudp-tx.c==================================================================================================
#include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <time.h> #include <string.h> //#include <curses.h> #include <unistd.h> #include <aio.h> #include <signal.h> #include <fcntl.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <netdb.h>
#define PORT 0xBAC0 #define MAXLINE 1500
#define LOG_FILE "bacnet0.log"
#define DIALOG_WIDTH 40 #define DIALOG_HEIGHT 20 #define CONTENT_WIDTH (DIALOG_WIDTH - 2)
uint8_t bqr_whois[]={ 0x81,0x0a,0x00,0x0c,0x01,0x20, 0xff,0xff,0x00,0xff,0x10,0x08
};
uint8_t brp_im[]={ 0x81,0x0b,0x00,0x19,0x01,0x20,0xff,0xff,0x00,0xff,0x10,0x00,0xc4,0x02,0x00,0x03, 0xf1,0x22,0x04,0x00,0x91,0x03,0x22,0x01,0x04 };
extern int32_t make_internet_address(int8_t * hostname,int32_t port,struct sockaddr_in *addrp);
int sockfd; char hname[128]={0}; uint8_t buffer[MAXLINE]; char *hello = "Hello from server"; struct sockaddr_in servaddr, cliaddr; struct hostent *hent=NULL;
// a simple log function, works similar to printf void bacnet0_log(const char *format, ... ) { va_list args; // argument list static FILE *logfile = NULL; // file pointer to the logfile char *fformat; // the modified format of the string which will be written to the logfile int length; // length of the format
if(!(format == NULL && logfile == NULL)) {
// open the logfile if not already opened
if(logfile == NULL) {
logfile = fopen(LOG_FILE, "w");
// if that doesn't work exit with an error message
if(logfile == NULL) {
fprintf(stderr, "Cannot open logfile %s\n", LOG_FILE);
exit(EXIT_FAILURE);
}
}
// if NULL is given as format, close the opened file
if(format != NULL) {
// increase length by 2 (for \n\0
length = strlen(format) + 2;
// allocate memory
fformat = malloc(sizeof(char) * length);
// copy the format over
strncpy(fformat, format, length - 2);
// append \n\0
//fformat[length - 2] = '\n';
fformat[length - 2] = '\0';
fformat[length - 1] = '\0';
// get the rest of the arguments
va_start(args, format);
// use vfprintf() to
vfprintf(logfile, fformat, args);
// forces the logmessage to be written into the file right now
fflush(logfile);
va_end(args);
// free the allocated memory for the format string
free(fformat);
}
else
{
// close the logfile
fclose(logfile);
}
}
}
#if defined(UBUNTU) void enable_kbd_signals(void) {
int fd_flags;
fcntl(0,F_SETOWN,getpid());
fd_flags = fcntl(0,F_GETFL);
fcntl(0,F_SETFL,(fd_flags|O_ASYNC));
//fcntl(0,F_SETFL,(fd_flags|O_RSYNC));
} #endif
#if 0 struct aiocb kbcbuf; void setup_aio_buffer(void) {
static char input[1];
kbcbuf.aio_fildes = 0;
kbcbuf.aio_buf = input;
kbcbuf.aio_nbytes = 1;
kbcbuf.aio_offset = 0;
kbcbuf.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
kbcbuf.aio_sigevent.sigev_signo = SIGIO;
} #endif
int8_t cmd_str[1024];
#if defined(UBUNTU) void on_input(int signum) {
fgets(cmd_str,128,stdin);
printf("cmd_str is %s\n",cmd_str);
if(strcmp(cmd_str,"quit\n") == 0)
{
exit(EXIT_SUCCESS);
}
if(strcmp(cmd_str,"whois\n") ==0)
{
make_internet_address("192.168.0.255",PORT,&cliaddr);
if(sendto(sockfd,bqr_whois,sizeof(bqr_whois),0,(struct sockaddr*)&cliaddr,sizeof(cliaddr)) == -1)
{
perror("udp send failed\n");
exit(EXIT_FAILURE);
}
}
memset(cmd_str,0,sizeof(cmd_str));
}
#endif
#if 0 void on_input(int signum) {
int c;
char *cp = (char*)kbcbuf.aio_buf;/*cast to char*/
if(aio_error(&kbcbuf) != 0)
{
perror("reading failed");
}
else
{
if(aio_return(&kbcbuf) == 1)
{
c=*cp;
if(c == 'q')
{
printf("that is it\n");
exit(EXIT_SUCCESS);
}
}
aio_read(&kbcbuf);
}
} #endif
int32_t make_internet_address(int8_t * hostname,int32_t port,struct sockaddr_in *addrp) {
struct hostent *hp;
bzero((void*)addrp,sizeof(struct sockaddr_in));
hp = gethostbyname(hostname);
if(hp == NULL)
return -1;
bcopy((void*)hp->h_addr,(void*)&addrp->sin_addr,hp->h_length);
addrp->sin_port = htons(port);
addrp->sin_family= AF_INET;
return 0;
}
int main(int argc, char* argv[])
{
#if 0
int sockfd;
char hname[128]={0};
uint8_t buffer[MAXLINE];
char *hello = "Hello from server";
struct sockaddr_in servaddr, cliaddr;
struct hostent *hent=NULL;
#endif
//gethostname(hname,sizeof(hname));
//hent = gethostbyname(hname);
if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 )
{
perror("socket creation failed");
exit(EXIT_FAILURE);
}
int optval =1;
setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST|SO_REUSEADDR,&optval,sizeof(int));
#if 0 struct timeval timeout; timeout.tv_sec = 6; timeout.tv_usec = 0; setsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,&timeout,sizeof(timeout));
memset(&servaddr, 0, sizeof(servaddr));
memset(&cliaddr, 0, sizeof(cliaddr));
// Filling server information
servaddr.sin_family = AF_INET; // IPv4
//servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(PORT);
//servaddr.sin_port = PORT;
// Bind the socket with the server address
if ( bind(sockfd, (const struct sockaddr *)&servaddr,
sizeof(servaddr)) < 0 )
{
perror("bind failed");
exit(EXIT_FAILURE);
}
int len, n;
len = sizeof(cliaddr); //len is value/resuslt
#endif
#if defined(UBUNTU) void on_input(int); signal(SIGIO,on_input); enable_kbd_signals(); #endif // setup_aio_buffer(); // aio_read(&kbcbuf);
memset(buffer,0,sizeof(buffer));
#if 0 //make_internet_address("192.168.0.104",PORT,&cliaddr); make_internet_address("192.168.0.255",PORT,&cliaddr); if(sendto(sockfd,bqr_whois,sizeof(bqr_whois),0,(struct sockaddr*)&cliaddr,sizeof(cliaddr)) == -1) { perror("udp send failed\n"); exit(EXIT_FAILURE);
}
#endif
#if 0 if(argc > 1) {
printf("argc is %d\n",argc);
if(strcmp(argv[1],"whois") == 0)
{
make_internet_address("192.168.0.255",PORT,&cliaddr);
if(sendto(sockfd,bqr_whois,sizeof(bqr_whois),0,(struct sockaddr*)&cliaddr,sizeof(cliaddr)) == -1)
{
perror("udp send failed\n");
}
}
}
#endif
#if 0 int fds[2];
int ifd=0;
if(pipe(fds) == -1)
{
perror("create pipe failed\n");
exit(EXIT_SUCCESS);
}
//ifd = dup(fds[1]);
close(0);
ifd = dup(fds[0]);
close(fds[0]);
if(ifd !=0)
{
perror("dup failed\n");
exit(EXIT_SUCCESS);
}
#endif
int ffd;
ffd = open("./ufifo",O_RDONLY);
if(ffd == -1)
{
perror("open fifo failed\n");
exit(EXIT_FAILURE);
}
while(1)
{
//pause();
#if 1 // printf("waiting on port %d\n",PORT); //n = recvfrom(sockfd, (char *)buffer, MAXLINE, 0, ( struct sockaddr *) &cliaddr, &len); // printf("recvfrom timeout\n"); // printf("buffer is %s\n",buffer);
//buffer[n] = '\0';
// printf("Client : %s\n", buffer);
//
#endif
#if 0 FILE * fp =NULL; fp = fdopen(ifd,"r");
if(fp ==NULL)
{
perror("fdopen failed\n");
exit(EXIT_SUCCESS);
}
#endif
read(ffd,buffer,sizeof(buffer));
// fgets(buffer,sizeof(buffer),stdin);
//read(ifd,buffer,sizeof(buffer));
//fgets(buffer,sizeof(buffer),fp);
//if(sendto(sockfd,buffer,strlen(buffer),0,(struct sockaddr*)&cliaddr,sizeof(cliaddr)) == -1)
//if(sendto(sockfd,brp_im,sizeof(brp_im),0,(struct sockaddr*)&cliaddr,sizeof(cliaddr)) == -1)
if(strcmp(buffer,"whois\n") == 0)
{
printf("got whois\n");
//make_internet_address("192.168.43.255",PORT,&cliaddr);
//make_internet_address("10.78.146.1",PORT,&cliaddr);
//make_internet_address("192.168.0.104",PORT,&cliaddr);
make_internet_address("192.168.0.255",PORT,&cliaddr);
//make_internet_address("127.0.0.1",PORT,&cliaddr);
char* test_udp_str = "hello UDP\n";
uint32_t stn=0;
if((stn = sendto(sockfd,test_udp_str,strlen(test_udp_str),0,(struct sockaddr*)&cliaddr,sizeof(cliaddr))) == -1)
{
perror("udp send failed\n");
exit(EXIT_FAILURE);
}
printf("udp send ok: %d\n",stn);
}
if(strcmp(buffer,"quit\n") == 0)
{
char *qt = "tx-quit\n";
if(sendto(sockfd,qt,strlen(qt),0,(struct sockaddr*)&cliaddr,sizeof(cliaddr)) == -1)
{
perror("udp send failed\n");
exit(EXIT_FAILURE);
}
printf("udp send ok\n");
printf("good-bye\n");
exit(EXIT_SUCCESS);
}
memset(buffer,0,sizeof(buffer));
// sleep(1);
}
}
//periodic.c=======================================================================
#include <stdio.h> #include <stdlib.h>
#include <signal.h> #include <sys/time.h> #include <unistd.h>
struct periodic_info { sigset_t alarm_sig; };
static int make_periodic (unsigned int period, struct periodic_info *info) { int ret; struct itimerval value;
/* Block SIGALRM in this thread */
sigemptyset (&(info->alarm_sig));
sigaddset (&(info->alarm_sig), SIGALRM);
pthread_sigmask (SIG_BLOCK, &(info->alarm_sig), NULL);
/* Set the timer to go off after the first period and then
repetitively */
#if 0 value.it_value.tv_sec = period/1000000; value.it_value.tv_usec = period%1000000; value.it_interval.tv_sec = period/1000000; value.it_interval.tv_usec = period%1000000; #endif
value.it_value.tv_sec = 1;
value.it_value.tv_usec = 0;
value.it_interval.tv_sec = 1;
value.it_interval.tv_usec = 0;
ret = setitimer (ITIMER_REAL, &value, NULL);
if (ret != 0)
perror ("Failed to set timer");
return ret;
}
static void wait_period (struct periodic_info *info) { int sig;
/* Wait for the next SIGALRM */
sigwait (&(info->alarm_sig), &sig);
}
int main(int argc,char*argv[]) { struct periodic_info info;
make_periodic (10000, &info);
while (1)
{
/* Do useful work */
printf("hello world!\n");
wait_period (&info);
}
}
//read_celsius.c==============================================================================
#include<sys/types.h> #include<errno.h> #include<string.h> #include<stdint.h> #include<termios.h> #include<sys/stat.h> #include<sys/select.h> #include<unistd.h> #include<fcntl.h> #include<stdio.h> #include<stdlib.h>
#include <termios.h>
//#define BLEN 128 #define BLEN BUFSIZ
int main(int argc, char** argv) { int fd; int wfd; int rfd;
fd_set fds;
struct timeval tv={5,0};
int retval;
int scnt=0;
int nread,i;
int tnread;
int nwrite=0;
int cnt=0;
int s=0;
int tlen=0;
char wbuff[64] = "Hello\n";
uint8_t recbuf[BLEN]={0};
uint8_t *precbuf=recbuf;
int cnt_rec=0;
int c;
char rbuff[BLEN] = {0};
// tv.tv_sec =5; // tv.tv_usec = 500000;
// fd = open("/dev/ttyUSB0",O_RDWR|O_NOCTTY|O_NDELAY); // fd = open("/dev/ttyUSB0",O_RDWR|O_NOCTTY); //fd = open("/dev/ttyUSB0",O_RDONLY); fd = open("/dev/ttyUSB0",O_RDWR); // fd = open("/dev/ttyS8",O_RDWR); // fd = open("/dev/ttyS4",O_RDWR);
// wfd = open("acom.log",O_WRONLY); // rfd = open(argv[1],O_RDONLY);
if(fd == -1)
{
perror("can not open serial port failed\n");
exit(EXIT_FAILURE);
}
printf("fd is %d\n",fd);
//tcflush(fd,TCIFLUSH);
tcflush(fd,TCIOFLUSH);
cnt_rec=0;
char cmd[128] = "dht11";
//tlen = write(fd,cmd,6);
#if 0 tlen = write(fd,"d",1); tlen = write(fd,"h",1); tlen = write(fd,"t",1); tlen = write(fd,"1",1); tlen = write(fd,"1",1); //sleep(1); #endif // printf("tx:the amount is %d\n",tlen);
memset(recbuf,0,sizeof(recbuf));
tlen = write(fd,cmd,5);
while(1)
{
FD_ZERO(&fds);
FD_SET(fd,&fds);
tv.tv_sec =5;
tv.tv_usec = 500000;
//sleep(1);
// tlen = write(fd,cmd,5);
retval = select(fd+1,&fds,NULL,NULL,&tv);
//retval = select(fd+1,&fds,NULL,NULL,NULL);
if(retval == -1)
{
printf("error:select\n");
close(fd);
exit(EXIT_FAILURE);
}
else if(retval)
{
if(FD_ISSET(fd,&fds))
{
// memset(recbuf,0,sizeof(recbuf));
tlen =read(fd,precbuf,BLEN);
// printf("m is %s\n",precbuf);
// printf("mlen is %d\n",tlen);
precbuf +=tlen;
//tlen =read(fd,recbuf,8);
#if 0 printf("rx:the amount is %d\n",tlen); printf("%d\n",recbuf[0]); printf("tlen is %d\n",tlen); #endif // printf("message is %s\n",recbuf); //printf("msg is %c %c %c %c\n",recbuf[0],recbuf[1],recbuf[2],recbuf[3]);
// tlen = write(fd,cmd,6);
}
}
#if 1 else {
precbuf = recbuf;
printf("message is %s\n",precbuf);
#if 0 int i=0; for(i=0;i<128;i++) printf("%c",precbuf[i]); printf("\n"); #endif memset(recbuf,0,sizeof(recbuf)); precbuf = recbuf; tlen = write(fd,cmd,6);
printf("send cmd %d\n",scnt++);
//printf("tlen is %d\n",tlen);
//exit(EXIT_FAILURE);
}
#endif
}
#if 0 while((nread =read(rfd,recbuf,BLEN)) > 0) {
nwrite= write(fd,recbuf,nread);
printf("nwrite is %d\n",nwrite);
tnread=0;
while(tnread != nwrite)
{
printf("---tnread is %d---\n",tnread);
nread = read(fd,rbuff,BLEN);
tnread +=nread;
printf("---nread is %d---\n",nread);
write(wfd,rbuff,nread);
}
}
close(wfd);
close(rfd);
close(fd);
#endif close(fd); printf("done\n"); return 0; }
//read_dat.sh===================================================================================== #!/bin/bash
awk 'BEGIN{
printf("it is 0x%x\n",0x33)
}
{
if($2*2==($4+$2))
{
print "====="
print "data is " $2 " " $4
print "dat is " $2*2
print NR
}
}' us.log
//readfile.sh============================================================================================
#!/bin/bash
if [ $# -lt 1 ]; then echo "error: need at least 1 parameter" else
cat $1 |while read line do echo $line for e in "$line" do echo $e done
done fi
//readfile2array.sh========================================================================================= #!/bin/bash
while read -a line
do
echo
//rformula.sh=================================================================================================
#!/bin/bash
#echo
#fi
rv=echo "scale=2;$1*2100/(65535-$1)"| bc
echo "The result is $rv"
#echo "hello world"
//rtd-uio.sh==================================================================================================
#!/bin/bash #like 0x31c1 if [ $# -lt 1 ];then echo "less parameters" exit fi
let a=$1
res=echo "scale=4;($a*2100)/(65535-$a)"|bc
echo "R is $res hom"
//scom.c================================================================================================================
#include<sys/types.h> #include<errno.h> #include<string.h> #include<termios.h> #include<sys/stat.h> #include<unistd.h> #include<fcntl.h> #include<stdio.h> #include<stdlib.h>
//#define BLEN 1024 #define BLEN BUFSIZ
int main(int argc, char** argv) { int fd; int wfd; int rfd;
int nread,i;
int tnread;
int nwrite=0;
int cnt=0;
int s=0;
char wbuff[64] = "Hello\n";
char recbuf[1024]={0};
int cnt_rec=0;
int c;
char rbuff[BLEN] = {0};
// fd = open("/dev/ttyUSB0",O_RDWR|O_NOCTTY|O_NDELAY); // fd = open("/dev/ttyUSB0",O_RDWR|O_NOCTTY); //fd = open("/dev/ttyUSB0",O_RDONLY); fd = open("/dev/ttyUSB0",O_RDWR); // fd = open("/dev/ttyS8",O_RDWR);
wfd = open("acom.log",O_WRONLY);
rfd = open(argv[1],O_RDONLY);
if(fd == -1)
{
perror("can not open serial port failed\n");
exit(EXIT_FAILURE);
}
printf("fd is %d\n",fd);
cnt_rec=0;
while((nread =read(rfd,recbuf,BLEN)) > 0)
{
nwrite= write(fd,recbuf,nread);
printf("nwrite is %d\n",nwrite);
tnread=0;
while(tnread != nwrite)
{
printf("---tnread is %d---\n",tnread);
nread = read(fd,rbuff,BLEN);
tnread +=nread;
printf("---nread is %d---\n",nread);
write(wfd,rbuff,nread);
}
}
close(wfd);
close(rfd);
close(fd);
printf("done\n");
return 0;
}
//snake.c======================================================================================================== #include <sys/types.h> #include <sys/time.h> #include <sys/stat.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <curses.h> #include <unistd.h> #include <aio.h> #include <signal.h> #include <fcntl.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <netdb.h>
#define PORT 8900 #define MAXLINE 1024
#define LOG_FILE "game.log"
#define DIALOG_WIDTH 40 #define DIALOG_HEIGHT 20 #define CONTENT_WIDTH (DIALOG_WIDTH - 2)
#define HEAD 'A' #define BODY 'O' #define BLANK ' ' #define DIR_UP 0 #define DIR_DOWN 1 #define DIR_LEFT 2 #define DIR_RIGHT 3
int dir= DIR_RIGHT; int cx=0; int cy=0; struct snake_body { int posx; int posy;
};
int body_len =2; struct snake_body body[20];
int c;
void set_colors() { // these don't actually have anything to do with binary, so we are free to use "normal" numbers init_pair(1, COLOR_RED, COLOR_BLACK); // red on black init_pair(2, COLOR_GREEN, COLOR_BLACK); // green on black init_pair(3, COLOR_YELLOW, COLOR_BLACK); // yellow on black init_pair(4, COLOR_BLUE, COLOR_BLACK); // blue on black init_pair(5, COLOR_MAGENTA, COLOR_BLACK); // magenta on black init_pair(6, COLOR_CYAN, COLOR_BLACK); // cyan on black init_pair(7, COLOR_WHITE, COLOR_BLACK); // white on black }
void end_curses() { endwin(); }
// a simple log function, works similar to printf void glog(const char *format, ... ) { va_list args; // argument list static FILE *logfile = NULL; // file pointer to the logfile char *fformat; // the modified format of the string which will be written to the logfile int length; // length of the format
if(!(format == NULL && logfile == NULL)) { // open the logfile if not already opened if(logfile == NULL) { logfile = fopen(LOG_FILE, "w"); // if that doesn't work exit with an error message if(logfile == NULL) { fprintf(stderr, "Cannot open logfile %s\n", LOG_FILE); exit(EXIT_FAILURE); } }
// if NULL is given as format, close the opened file
if(format != NULL) {
// increase length by 2 (for \n\0
length = strlen(format) + 2;
// allocate memory
fformat = malloc(sizeof(char) * length);
// copy the format over
strncpy(fformat, format, length - 2);
// append \n\0
fformat[length - 2] = '\n';
fformat[length - 1] = '\0';
// get the rest of the arguments
va_start(args, format);
// use vfprintf() to
vfprintf(logfile, fformat, args);
// forces the logmessage to be written into the file right now
fflush(logfile);
va_end(args);
// free the allocated memory for the format string
free(fformat);
}
else
{
// close the logfile
fclose(logfile);
}
} }
// create a basic dialog with title which looks like this: // // +--------------------------------------+ // +---------------- TITLE ---------------+ // +--------------------------------------+ // | | // | | // | | // | | // | | // | | // | | // | | // | | // | | // | | // | | // | | // | | // | | // | | // +--------------------------------------+ // WINDOW *create_dialog_window(const char *title) { WINDOW *win; int sx, sy, i, u, startpos;
// get the screen size getmaxyx(stdscr, sy, sx); // create a little window in the center of the screen with a border and a size of 40x20 win = newwin(DIALOG_HEIGHT, DIALOG_WIDTH, sy / 2 - DIALOG_HEIGHT / 2, sx / 2 - DIALOG_WIDTH / 2);
// create the border wborder(win, '|', '|', '-', '-', '+', '+', '+', '+');
// fill the first two lines with "-" and "+" on the border for(u = 1; u <= 2; u++) { for(i = 0; i < DIALOG_WIDTH; i++) { mvwprintw(win, u, i, "%c", i == 0 || i == DIALOG_WIDTH - 1 ? '+' : '-'); } }
// print the title in the middle of the dialog startpos = DIALOG_WIDTH / 2 - strlen(title) / 2; // print a space before the title mvwprintw(win, 1, startpos - 1, " "); // print the title itself mvwprintw(win, 1, startpos, "%s", title); // print a space after the title mvwprintw(win, 1, startpos + strlen(title), " "); return win; }
// creates a dialog with menu entries, you can press numbers to select a menu entry and close the dialog int create_numbered_dialog(const char *title, const char *contents, int lines) { WINDOW *win = create_dialog_window(title); int i, ch, number = 0;
// insert menu entries into the dialog for(i = 0; i < lines; i++) { mvwprintw(win, i + 3, 1, &contents[i * CONTENT_WIDTH], i + 1); }
// display the dialog wrefresh(win);
// wait for some input while((ch = wgetch(win))) { // error? begin again. //if(ch == ERR) continue;
// select the first menu entry if enter is pressed
if(ch == '\n') ch = '1';
// a number pressed?
if(ch >= '0' && ch <= '9') {
number = ch - '0';
// prevent from handling numbers which are > than the number of menu entries
if(ch - '0' <= lines) {
// get out of the loop
break;
}
}
}
// delete the window delwin(win);
// return the number pressed return number; }
// displays the main menu int display_menu() { // the contents of the menu // %i will be replaced with the number of the menu entry char menu[][CONTENT_WIDTH] = { "%i) Start the game", "%i) Highscores", "%i) Controls", "%i) Help", "%i) Clear Highscores", "%i) Exit" }; // create a numbered dialog return create_numbered_dialog("MENU", (char *)menu, 6); }
void main_menu() { int selected_menu_entry; do { selected_menu_entry = display_menu(); if(selected_menu_entry == 1) { // run the game //run(); } else if(selected_menu_entry == 2) { // display the highscores //show_highscores(); } else if(selected_menu_entry == 3) { // display a dialog which explains the controls of the game //display_controls(); } else if(selected_menu_entry == 4) { // display a dialog which explains the elements of the game //display_help(); } else if(selected_menu_entry == 5) { // clear highscores #if 0 if(clear_score_dialog() == 1) { clear_highscore(); } #endif } // leave if the menu entry "exit" is chosen } while(selected_menu_entry != 6); }
#if 0 void enable_kbd_signals(void) {
int fd_flags;
fcntl(0,F_SETOWN,getpid());
fd_flags = fcntl(0,F_GETFL);
fcntl(0,F_SETFL,(fd_flags|O_ASYNC));
//fcntl(0,F_SETFL,(fd_flags|O_RSYNC));
} #endif
struct aiocb kbcbuf; void setup_aio_buffer(void) {
static char input[1];
kbcbuf.aio_fildes = 0;
kbcbuf.aio_buf = input;
kbcbuf.aio_nbytes = 1;
kbcbuf.aio_offset = 0;
kbcbuf.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
kbcbuf.aio_sigevent.sigev_signo = SIGIO;
}
int set_ticker(int n_msecs) { struct itimerval new_timeset; long n_sec,n_usec;
n_sec = n_msecs/1000;
n_usec = (n_msecs%1000)*1000L;
new_timeset.it_interval.tv_sec = n_sec;
new_timeset.it_interval.tv_usec = n_usec;
new_timeset.it_value.tv_sec = n_sec;
new_timeset.it_value.tv_usec = n_usec;
return setitimer(ITIMER_REAL,&new_timeset,NULL);
}
void on_timer(int signum) { int j; static int i=0; move(10,10); printw("hello world %d",i++); refresh();
switch(dir)
{
case DIR_UP:
cx -=1;
break;
case DIR_DOWN:
cx +=1;
break;
case DIR_LEFT:
cy -=1;
break;
case DIR_RIGHT:
cy +=1;
break;
}
move(11,10);
printw("body_len is %d",body_len);
#if 1 for(j=body_len;j>0;j--) {
body[j].posx = body[j-1].posx;
body[j].posy = body[j-1].posy;
}
body[j].posx =cx;
body[j].posy =cy;
for(j=0;j<body_len;j++)
{
move(body[j].posx,body[j].posy);
if(j ==0)
{
addch(HEAD);
}
else
{
addch(BODY);
}
}
move(body[body_len].posx,body[body_len].posy);
addch(BLANK);
#endif refresh(); }
int onkey=0; void on_input(int signum) { #if 0 int c = getch(); move(15,15); addch(c);
#endif
char *cp = (char*)kbcbuf.aio_buf;/*cast to char*/
if(aio_error(&kbcbuf) != 0)
{
perror("reading failed");
}
else
{
if(aio_return(&kbcbuf) == 1)
{
c=*cp;
onkey = c;
move(15,15);
addch(c);
refresh();
#if 1
if(c == 'x')
{
switch(dir)
{
case DIR_UP:
body[body_len].posx = body[body_len -1].posx+1;
body[body_len].posy = body[body_len -1].posy;
body_len++;
break;
case DIR_DOWN:
body[body_len].posx = body[body_len -1].posx-1;
body[body_len].posy = body[body_len -1].posy;
body_len++;
break;
case DIR_LEFT:
body[body_len].posx = body[body_len -1].posx;
body[body_len].posy = body[body_len -1].posy+1;
body_len++;
break;
case DIR_RIGHT:
body[body_len].posx = body[body_len -1].posx;
body[body_len].posy = body[body_len -1].posy-1;
body_len++;
break;
}
int m;
for(m=0;m<body_len;m++)
{
move(body[m].posx,body[m].posy);
if(m ==0)
{
addch(HEAD);
}
else
{
addch(BODY);
}
}
refresh();
}
#endif
if(c == 'q')
{
endwin();
printf("that is it\n");
exit(EXIT_SUCCESS);
}
}
aio_read(&kbcbuf);
}
}
void init_curses() {
#if _BSD_SOURCE || _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600 // by default, ncurses stops the execution of the program for // 1 second if escape is pressed. Disable this behaviour. setenv("ESCDELAY", "0", 1); #endif
initscr();
// get more control over the input
cbreak();
// getch() returns ERR if no input is present and doesn't wait
//nodelay(stdscr, TRUE);
// don't echo the inserted keys to the screen
noecho();
// colors!
start_color();
set_colors();
// also grab keys like F1 etc.
keypad(stdscr, TRUE);
}
int main(int argc, char* argv[]) {
#if defined(use_UDP) int sockfd; char hname[128]={0}; char buffer[MAXLINE]; char *hello = "Hello from server"; struct sockaddr_in servaddr, cliaddr; struct hostent *hent=NULL;
gethostname(hname,sizeof(hname));
hent = gethostbyname(hname);
if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 )
{
perror("socket creation failed");
exit(EXIT_FAILURE);
}
memset(&servaddr, 0, sizeof(servaddr));
memset(&cliaddr, 0, sizeof(cliaddr));
// Filling server information
servaddr.sin_family = AF_INET; // IPv4
//servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(PORT);
//servaddr.sin_port = PORT;
// Bind the socket with the server address
if ( bind(sockfd, (const struct sockaddr *)&servaddr,
sizeof(servaddr)) < 0 )
{
perror("bind failed");
exit(EXIT_FAILURE);
}
int len, n;
len = sizeof(cliaddr); //len is value/resuslt
#endif
WINDOW *xw;
void on_input(int);
signal(SIGIO,on_input);
//enable_kbd_signals();
setup_aio_buffer();
aio_read(&kbcbuf);
set_ticker(200);
signal(SIGALRM,on_timer);
init_curses();
curs_set(0);
int ti,tj;
#if 0 body[0].posx=30; body[0].posy=30;
body[1].posx=30;
body[1].posy=29;
#endif
for(ti=0;ti<body_len;ti++)
{
body[ti].posx=30;
body[ti].posy=30-ti;
move(body[ti].posx,body[ti].posy);
if(ti == 0)
{
addch(HEAD);
}
else
{
addch(BODY);
}
}
refresh();
cx = body[0].posx;
cy = body[0].posy;
while(1)
{
switch(onkey)
{
case 'w':
dir = DIR_UP;
break;
case 's':
dir = DIR_DOWN;
break;
case 'a':
dir = DIR_LEFT;
break;
case 'd':
dir = DIR_RIGHT;
break;
}
#if defined(use_UDP)
//pause();
move(20,25);
//printf("waiting on port %d\n",PORT);
printw("waiting on port %d\n",PORT);
refresh();
#if 0
n = recvfrom(sockfd, (char *)buffer, MAXLINE,
MSG_WAITALL, ( struct sockaddr *) &cliaddr,
&len);
#endif
n = recvfrom(sockfd, (char *)buffer, MAXLINE,
0, ( struct sockaddr *) &cliaddr,
&len);
buffer[n] = '\0';
//printf("Client : %s\n", buffer);
move(25,25);
printw("Client : %s\n", buffer);
refresh();
#endif //sleep(5); } // main_menu(); // xw=create_dialog_window("hello"); // wrefresh(xw); // refresh();
// sleep(4);
end_curses();
}
//tcom.c========================================================================================================== #include<sys/types.h> #include<errno.h> #include<string.h> #include<termios.h> #include<sys/stat.h> #include<unistd.h> #include<fcntl.h> #include<stdio.h> #include<stdlib.h> #include<pthread.h>
//#define BLEN 1024 #define BLEN BUFSIZ
int fd;
int flag=0;
char rbuf[BLEN] = {0}; char wbuf[BLEN] = {0};
void *read_com(void *ptr) { int nread=0; int tnread=0; int cnt=0; while(1) { if(flag ==1) {
printf("read com\r\n");
nread = read(fd,rbuf,sizeof(rbuf)-2);
// printf("nread is %d\r\n",nread);
printf("rbuf is %s\r\n",rbuf);
memset(rbuf,sizeof(rbuf),0);
if(nread)
{
tnread += nread;
nread =0;
// printf("tnread is %d\r\n",tnread);
}
flag=0;
}
}
}
void *write_com(void *ptr) { int nwrite=0;
int cnt=0;
wbuf[0] = 'h';
wbuf[1] = 'e';
wbuf[2] = 'l';
wbuf[3] = 'l';
wbuf[4] = 'o';
wbuf[5] = '\r';
wbuf[6] = '\n';
wbuf[7] = '\0';
while(1)
{
printf("write com\r\n");
nwrite= write(fd,wbuf,strlen(wbuf));
//printf("nwrite is %d\r\n",nwrite);
memset(wbuf,sizeof(wbuf),0);
flag =1;
sleep(6);
cnt++;
if(cnt > 3)
{
//cnt=0;
//fsync(fd);
sleep(6);
break;
}
}
}
int main(int argc, char** argv) {
fd = open("/dev/ttyS7",O_RDWR);
if(fd == -1)
{
perror("can not open serial port failed\n");
exit(EXIT_FAILURE);
}
printf("fd is %d\n",fd);
pthread_t thread1,thread2;
int iret1,iret2;
iret1 = pthread_create(&thread1,NULL,read_com,NULL);
iret2 = pthread_create(&thread2,NULL,write_com,NULL);
pthread_join(thread1,NULL);
pthread_join(thread1,NULL);
printf("thread 1 returns %d\n",iret1);
printf("thread 2 returns %d\n",iret2);
close(fd);
printf("done\n");
return 0;
}
//test_bacnet.sh======================================================================================
#!/bin/bash IP=192.168.0.108 PORT=47808 echo "whois" echo "whois" > /dev/udp/${IP}/${PORT}
sleep 5
echo "whois" #echo "whois" > /dev/udp/192.168.0.105/47808 echo "whois" > /dev/udp/${IP}/${PORT}
sleep 5 echo "quit" #echo "quit" > /dev/udp/192.168.0.105/47808 echo "quit" > /dev/udp/${IP}/${PORT}
//test-udp-tx-rx.sh========================================================================================================== #!/bin/bash
echo whois > ufifo sleep 1 echo quit > ufifo sleep 1 echo good-bye
//tk.py============================================================================================================
#!/usr/bin/python
from tkinter import *
def hello(): print("hello")
root=Tk() button=Button(root,text='click me',command=hello) button.pack() root.mainloop()
//==============================================================================
//OOPPGGTT //==============================================================================
//block.cpp=======================================================================================
#include "common.h"
block::block() { addChild(&binfile); addChild(&reserved); }
block::block(Element* elem, image* img): block() { elem = findElement(elem, "block"); if( elem == nullptr ) return;
if( FindAttribute(elem, "blockType") )
blockType = getBlockType(FindAttribute(elem, "blockType")->Value());
if( FindAttribute(elem, "blockSize") )
blockSize = hex2int(FindAttribute(elem, "blockSize")->Value(), 8);
switch( blockType )
{
case OTA:
binfile.addChild(img->OTApackage);
break;
case FCT:
binfile.addChild(img->FCTpackage);
break;
default:
break;
}
if( blockSize > gsize() )
reserved.set(blockSize - gsize());
}
block::block(Element* elem, image* img, FILE* fp): block() { elem = findElement(elem, "block"); if( elem == nullptr ) return;
if( FindAttribute(elem, "blockType") )
blockType = getBlockType(FindAttribute(elem, "blockType")->Value());
if( FindAttribute(elem, "blockSize") )
blockSize = hex2int(FindAttribute(elem, "blockSize")->Value(), 8);
switch( blockType )
{
case OTA:
img->OTApackage = new package(nullptr, fp);
binfile.addChild(img->OTApackage);
break;
case FCT:
img->FCTpackage = new fctpack(elem, fp);
binfile.addChild(img->FCTpackage);
break;
default:
break;
}
if( blockSize > gsize() )
reserved.set(blockSize - gsize(), fp);
}
block::blockType_t block::getBlockType(const char* type) { for(uint8_t i = 0; i < 4; ++i) { if( strcmp(type, blockTypeList[i]) == 0 ) return (blockType_t)i; } return NONE; }
//common.cpp======================================================================================================
#include "common.h"
#ifdef TEST extern const char* ftest; #endif // TEST
const char* typeList[] = {"NONE", "OPGT", "EIGT", "EIET", "OPDT", "EIDT", "PDGT"};
uint32_t hex2int(const char* str, uint8_t digit) { char c; uint32_t res = 0;
if(str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
str += 2;
for(int i = 0; i < digit; ++i)
{
c = *str;
if(c >= '0' && c <= '9')
c = c - '0';
else if(c >= 'a' && c <= 'f')
c = c - 'a' + 10;
else if(c >= 'A' && c <= 'F')
c = c - 'A' + 10;
else
break;
res <<= 4;
res |= c;
++str;
}
return res;
}
void int2hex(uint8_t byte, char* str) { sprintf(str, "%02x", byte); }
void hexString2Array(const char* key, uint8_t* buf, uint32_t len) { for(uint32_t i = 0; i < len; ++i) buf[i] = hex2int(&key[i*2], 2); }
uint32_t version2Int(const char* str, uint8_t digit) { char c; uint8_t n; uint32_t res = 0;
for(int i = 0; i < digit; ++i)
{
n = 0;
while( (c = *str) && c >= '0' && c <= '9' )
{
c = c - '0';
++str;
n = n * 10 + c;
}
c = *str;
res |= n << (i * 8);
if( c != '.' )
break;
++str;
}
return res;
}
Element* findElement(Element* elem, const char* name) { if(elem == nullptr) return nullptr;
Element* res;
if( strcmp(elem->Value(), name) == 0 )
return elem;
if( elem->FirstChildElement() != nullptr )
{
elem = elem->FirstChildElement();
while( elem )
{
res = findElement(elem, name);
if( res )
return res;
elem = elem->NextSiblingElement();
}
}
return nullptr;
}
Attribute* FindAttribute(Element* elem, const char* name) { Attribute* attr = elem->FindAttribute(name); if( attr ) return attr; cout << name << " not found. Skip. " << endl; return nullptr; }
list<Element*> makeList(Element* elem, const char* str) { list<Element*> elems; while(elem) { elems.push_back(elem); elem = elem->NextSiblingElement(str); } return elems; }
void getParams(Element* elem) { if( findElement(elem, "SignToolPath") ) SignToolPath = findElement(elem, "SignToolPath")->GetText(); if( findElement(elem, "WorkerName") ) WorkerName = findElement(elem, "WorkerName")->GetText(); if( findElement(elem, "FixtureName") ) FixtureName = findElement(elem, "FixtureName")->GetText(); if( findElement(elem, "SignEnv") ) SignEnv = findElement(elem, "SignEnv")->GetText(); if( findElement(elem, "Encrypt") ) IsEncrypt = findElement(elem, "Encrypt")->IntText(); if( findElement(elem, "DestinationAddress") ) destAddrTable = SetDestAddrTable(findElement(elem, "DestinationAddress")); if( IsEncrypt ) { ProvData = new provdata(findElement(elem, "ProvDataFile")); rootKey = ProvData->rootKey; devKey = ProvData->deviceKey; } if( toolType == OPGT || toolType == OPDT ) { encKey = deriveKey; decKey = deriveKey; } else if( toolType == EIGT) { encKey = deriveKey; decKey = deriveKey; } else if( toolType == EIET) { encKey = devKey; decKey = deriveKey; } else if( toolType == EIDT ) { encKey = devKey; decKey = devKey; } }
bool signFile(const char* file, const char* signToolPath, const char* fixtureName, const char* workerName, uint8_t* buf) { //rawkeysigner.exe -in [file] -env QA -cert "Fixture XXX" -worker GWP_firmware -out [output file]
cout << "Signing... ";
const char* signingTool = "\\RawKeySigner.exe";
const char* option1 = " -in ";
const char* option2 = " -env ";
const char* option3 = " -cert ";
const char* option4 = " -worker ";
const char* option5 = " -out ";
const char* signatureFile = "temp.sig ";
remove(signatureFile);
char command[256] = {0};
strcat(command, signToolPath);
strcat(command, signingTool);
if( access(command, F_OK) != 0 )
{
cout << "Signing tool not found. " << endl;
return false;
}
strcat(command, option1);
strcat(command, file);
strcat(command, option2);
if( SignEnv == nullptr )
{
cout << "Missing sign environment. " << endl;
return false;
}
strcat(command, SignEnv);
strcat(command, option3);
if( fixtureName == nullptr )
{
cout << "Missing fixture name. " << endl;
return false;
}
strcat(command, fixtureName);
strcat(command, option4);
if( workerName == nullptr )
{
cout << "Missing worker name. " << endl;
return false;
}
strcat(command, workerName);
strcat(command, option5);
strcat(command, signatureFile);
char strbuf[256];
FILE* pPipe;
if( ( pPipe = _popen(command, "r") ) == nullptr )
perror("Fail to open a pipe. ");
char* str;
char* pos;
while( (str = fgets( strbuf, 256, pPipe )) )
{
// cout << str; if(strcmp(str, "Analyzing signature ...Done\n") == 0) { fgets( strbuf, 256, pPipe ); pos = strstr(str, "pR: "); if(pos == nullptr) break; pos += strlen("pR: ");
for(int i = 0; i < 32; ++i)
buf[i] = hex2int(pos + i * 3, 2);
fgets( strbuf, 256, pPipe );
pos = strstr(str, "pS: ");
if(pos == nullptr)
break;
pos += strlen("pS: ");
for(int i = 0; i < 32; ++i)
buf[i+32] = hex2int(pos + i * 3, 2);
FILE* fp = fopen(signatureFile, "rb");
fclose(fp);
remove(signatureFile);
cout << "done. " << endl;
return true;
}
}
FILE* fp = fopen(signatureFile, "rb");
fclose(fp);
remove(signatureFile);
cout << "fail. " << endl;
return false;
}
bool verifySignature(const char* file, const char* sig, const char* verifyToolPath, const char* cert) { //VerifySignature.exe -in firmware.bin -sig firmware.sig -cert GWP_firmware.crt
cout << "Verify... ";
const char* verifyTool = "\\VerifySignature -in ";
const char* option1 = " -sig ";
const char* option2 = " -cert ";
uint8_t sigP[SigLen];
uint8_t sigO[SigLen];
FILE* fp = fopen(sig, "rb+");
fread(sigP, SigLen, 1, fp);
for(uint8_t i = 0; i < SigLen / 2; ++i)
sigO[i] = sigP[SigLen/2-i-1];
for(uint8_t i = SigLen / 2; i < SigLen; ++i)
sigO[i] = sigP[SigLen-i-1+SigLen/2];
fseek(fp, 0, SEEK_SET);
fwrite(sigO, SigLen, 1, fp);
fclose(fp);
char command[256] = {0};
strcat(command, verifyToolPath);
strcat(command, verifyTool);
strcat(command, file);
strcat(command, option1);
strcat(command, sig);
strcat(command, option2);
strcat(command, verifyToolPath);
strcat(command, "\\");
strcat(command, cert);
char strbuf[256];
FILE* pPipe;
if( ( pPipe = _popen(command, "r") ) == nullptr )
perror("Fail to open a pipe. ");
char* str;
char* pos;
while( (str = fgets( strbuf, 256, pPipe )) )
{
pos = strstr(str, "Verifying signature... ");
if( pos == nullptr )
continue;
pos += strlen("Verifying signature... ");
pos = strstr(pos, "OK");
if( pos == nullptr )
break;
cout << "done. " << endl;
return true;
}
cout << "fail. " << endl;
return false;
}
void generateIV(uint8_t* value, uint8_t len) { uint8_t seedLen = sizeof(uint32_t) + sizeof(uint64_t) + len; uint8_t *seed; seed = new uint8_t[seedLen]; uint32_t time = clock(); uint64_t addr = (uint64_t)seed; memcpy(&seed[0], &time, sizeof(uint32_t)); memcpy(&seed[sizeof(uint32_t)], &addr, sizeof(uint64_t)); memcpy(&seed[sizeof(uint32_t)+sizeof(uint64_t)], &value, len);
RandomArray(seed, seedLen, value, len);
delete[] seed;
};
toolType_t getToolType(const char* type) { for(uint8_t i = 0; i < 7; ++i) { if( strcmp(type, typeList[i]) == 0 ) return (toolType_t)i; } return NONE; }
vector4d* SetDestAddrTable(Element* element) { Attribute* attribute; Element* findelem; int mcuNumber = 0;
findelem = element->FirstChildElement();
while( findelem )
{
++mcuNumber;
findelem = findelem->NextSiblingElement();
}
vector4d* destAddrTable = new vector4d[mcuNumber];
findelem = element->FirstChildElement();
for(int i = 0; i < mcuNumber; ++i )
{
attribute = FindAttribute(findelem, "Firmware");
destAddrTable[i][0] = hex2int(attribute->Value(), 8);
attribute = FindAttribute(findelem, "Bootloader");
destAddrTable[i][1] = hex2int(attribute->Value(), 8);
attribute = FindAttribute(findelem, "Configuration");
destAddrTable[i][2] = hex2int(attribute->Value(), 8);
attribute = FindAttribute(findelem, "OTAkey");
destAddrTable[i][3] = hex2int(attribute->Value(), 8);
findelem = findelem->NextSiblingElement();
}
return destAddrTable;
}
void beforeExit() { if( destAddrTable ) delete[] destAddrTable; }
//common.h============================================================================================================
#ifndef _COMMON_H #define _COMMON_H
#include <io.h> #include #include #include #include
#include "Tnode.h" #include "tinyxml2.h" #include "crypt.h"
#define HeaderLength 0x200 #define EncKeyLen 0x10 #define RootKeyLen 0x20 #define IVLen 0x10 #define DigestLen 0x20 #define SeedLen 0x20 #define SigLen 0x40
using namespace std;
enum toolType_t { NONE = 0, OPGT = 1, EIGT = 2, EIET = 3, OPDT = 4, EIDT = 5, PDGT = 6,
};
typedef tinyxml2::XMLElement Element; typedef const tinyxml2::XMLAttribute Attribute; typedef uint32_t vector4d[4];
class provdata; class moduleinfo; class header; class file; class module; class package; class fctpack; class block; class image;
uint32_t hex2int(const char* str, uint8_t digit); void int2hex(uint8_t byte, char* str); void hexString2Array(const char* key, uint8_t* buf, uint32_t len); uint32_t version2Int(const char* str, uint8_t digit); Element* findElement(Element* elem, const char* name); Attribute* FindAttribute(Element* elem, const char* name); list<Element*> makeList(Element* elem, const char* str); void getParams(Element* elem); bool signFile(const char* file, const char* signToolPath, const char* fixtureName, const char* workerName, uint8_t* buf); bool verifySignature(const char* file, const char* sig, const char* verifyToolPath, const char* cert); void generateIV(uint8_t* value, uint8_t len); toolType_t getToolType(const char* type); vector4d* SetDestAddrTable(Element* element); void beforeExit();
#ifdef MAIN provdata* ProvData = nullptr; const char* SignToolPath = nullptr; const char* WorkerName = nullptr; const char* FixtureName = nullptr; const char* SignEnv = nullptr; bool IsEncrypt = true; uint8_t* rootKey = nullptr; uint8_t* devKey = nullptr; uint8_t deriveKey[EncKeyLen]; const uint8_t* encKey = nullptr; const uint8_t* decKey = nullptr; toolType_t toolType = NONE; vector4d* destAddrTable = nullptr;
#else extern provdata* ProvData; extern const char* SignToolPath; extern const char* WorkerName; extern const char* FixtureName; extern const char* SignEnv; extern bool IsEncrypt; extern uint8_t* rootKey; extern uint8_t* devKey; extern uint8_t deriveKey[EncKeyLen]; extern const uint8_t* encKey; extern const uint8_t* decKey; extern toolType_t toolType; extern vector4d* destAddrTable;
#endif
class moduleinfo: public Tnode {
public:
static uint32_t offAccum;
Tnode owner = {(char*)"owner", 1};
Tnode type = {(char*)"type", 1};
Tnode productID = {(char*)"productID", 4};
Tnode HWversion = {(char*)"HWversion", 4};
Tnode version = {(char*)"version", 4};
Tnode offset = {(char*)"offset", 4};
Tnode moduleSize = {(char*)"moduleSize", 4};
Tnode destAddr = {(char*)"destAddr", 4};
Tnode reserved = {(char*)"reserved", 22};
moduleinfo();
moduleinfo(Element* elem);
moduleinfo(FILE* fp);
};
class header: public Tnode {
public:
Tnode deriveParam = {(char*)"deriveParam", 32};
Tnode reserved0 = {(char*)"reserved0", 32};
Tnode headerIV = {(char*)"headerIV", 16};
Tnode packageSize = {(char*)"packageSize", 4};
Tnode headerLength = {(char*)"headerLength", 4};
Tnode version = {(char*)"version", 4};
Tnode moduleCount = {(char*)"moduleCount", 4};
Tnode moduleinfos;
Tnode enryptionIV = {(char*)"enryptionIV", 16};
Tnode reserved = {(char*)"reserved"};
Tnode signature = {(char*)"signature", 64};
Tnode signArea;
Tnode encryptArea;
Tnode fixArea;
Tnode plainArea;
Tnode signandfixArea;
Tnode sigandvarArea;
Tnode nosignArea;
header();
void set(void);
void set(Element* elem);
void read(FILE* fp);
void readcipher(FILE* fp);
void random(void);
};
class file: public Tnode {
public: Tnode padding = {(char*)"padding"};
file();
file(const char* n, uint32_t s = 0);
};
class module: public Tnode {
public:
Tnode files = {(char*)"files"};
Tnode padding = {(char*)"padding"};
#ifdef SIGNMODULE Tnode signature = {(char*)"signature", 64}; #endif module(); module(Element* elem); module(moduleinfo& mod, FILE* fp); };
class package: public Tnode {
public: header header; Tnode modules; Tnode signature = {(char*)"signature", 64}; Tnode encryptArea; Tnode signArea;
package();
package(Element* elem);
package(Element* elem, FILE* fp);
};
class fctpack: public Tnode {
public: Tnode encryptIV = {(char*)"encryptIV", 16}; Tnode part1 = {(char*)"part1"}; Tnode offset = {(char*)"offset", 4}; Tnode part2 = {(char*)"part2"}; Tnode fixArea; Tnode encryptArea;
uint32_t offsetLoc;
fctpack();
fctpack(Element* elem);
fctpack(Element* elem, FILE* fp);
void random();
};
class block: public Tnode {
const char* blockTypeList[4] = {"NONE", "OTA", "FCT", "DATA"};
enum blockType_t
{
NONE = 0,
OTA = 1,
FCT = 2,
DATA = 3,
};
blockType_t getBlockType(const char* type);
public: Tnode binfile = {(char*)"binfile"}; Tnode reserved = {(char*)"reserved"};
uint32_t blockSize = 0;
blockType_t blockType = NONE;
block();
block(Element* elem, image* img);
block(Element* elem, image* img, FILE* fp);
};
class image: public Tnode {
public: Tnode head = {(char*)"head"}; Tnode blocks; Tnode tail = {(char*)"tail"};
package* OTApackage;
fctpack* FCTpackage;
file* DATApackage;
uint32_t headerSize;
uint32_t flashSize;
image();
image(Element* elem);
image(Element* elem, FILE* fp);
};
class provdata: public Tnode {
public:
Tnode provMagic = {(char*)"provMagic", 4};
Tnode provDataVersion = {(char*)"provDataVersion", 4};
Tnode eccCapacity = {(char*)"eccCapacity", 4};
Tnode productType = {(char*)"productType", 4};
Tnode signPublicKey = {(char*)"signPublicKey", 64};
Tnode latchKey = {(char*)"latchKey", 32};
Tnode ioProtectKey = {(char*)"ioProtectKey", 32};
Tnode encryptedWriteKey = {(char*)"encryptedWriteKey", 32};
Tnode encryptedReadKey = {(char*)"encryptedReadKey", 32};
Tnode rootKey = {(char*)"rootKey", 32};
Tnode deviceKey = {(char*)"deviceKey", 32};
Tnode MAC = {(char*)"MAC", 8};
Tnode serialNumber = {(char*)"serialNumber", 32};
Tnode reserved = {(char*)"reserved", 136};
Tnode hashData = {(char*)"hashData", 32};
Tnode nonce = {(char*)"nonce", 32};
Tnode hashArea;
Tnode encryptArea;
provdata();
provdata(Element* elem);
bool provIsEncrypt();
};
#endif // _COMMON_H
//crypt.cpp==================================================================================================================== #include <stdint.h> #include <assert.h> #include "config.h" #include "cryptlib.h" #include "hex.h" #include "secblock.h" #include "modes.h" #include "aes.h" #include "filters.h" #include "files.h" #include "smartptr.h" #include "hmac.h" #include "sha.h" #include "randpool.h"
#define keyLen 16 #define RootkeyLen 32 #define DIGEST_LENGTH 0x20
using namespace CryptoPP;
class bytes { private: uint8_t* byte = nullptr; uint32_t length = 0;
public: bytes(void) {}
bytes(const char* value, uint32_t len)
{
length = len;
byte = new uint8_t[len];
memcpy(byte, value, len);
}
bytes(const uint8_t* value, uint32_t len)
{
length = len;
byte = new uint8_t[len];
memcpy(byte, value, len);
}
~bytes()
{
if(byte != nullptr)
delete[] byte;
byte = nullptr;
length = 0;
}
bytes(const bytes& lv)
{
if(byte != nullptr)
delete[] byte;
length = lv.length;
byte = new uint8_t[length];
memcpy(byte, lv.byte, length);
}
bytes operator+ (const bytes& lv)
{
uint8_t sum[length + lv.length];
memcpy(sum, byte, length);
memcpy(&sum[length], lv.byte, lv.length);
return bytes(sum, length + lv.length);
}
bytes& operator= (const bytes& lv)
{
if(byte != nullptr)
delete[] byte;
length = lv.length;
byte = new uint8_t[length];
memcpy(byte, lv.byte, length);
return *this;
}
uint32_t size(void)
{
return length;
}
uint8_t* value(void)
{
return byte;
}
};
static uint32_t hex2int(const char* str, uint8_t digit) { char c; uint32_t res = 0;
if(str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
str += 2;
for(int i = 0; i < digit; ++i)
{
c = *str;
if(c >= '0' && c <= '9')
c = c - '0';
else if(c >= 'a' && c <= 'f')
c = c - 'a' + 10;
else if(c >= 'A' && c <= 'F')
c = c - 'A' + 10;
else
break;
res <<= 4;
res |= c;
++str;
}
return res;
}
void SetByteArray(const char* key, uint8_t* buf, int len) { for(int i = 0; i < len; ++i) buf[i] = hex2int(&key[i*2], 2); }
void AES_CTR(const uint8_t *key, const uint8_t *iv, uint8_t ivlen, uint8_t *in, uint8_t *out, uint32_t buflen) { CTR_Mode::Encryption aes(key, ivlen, iv); ArraySource(in, buflen, true, new StreamTransformationFilter(aes, new ArraySink(out, buflen))); }
bytes HmacArray(const uint8_t *key, bytes seed) { uint8_t len = seed.size(); uint8_t out[DIGEST_LENGTH]; member_ptr mac; mac.reset(new HMAC(key, DIGEST_LENGTH)); ArraySource(seed.value(), len, true, new HashFilter(*mac, new ArraySink(out, DIGEST_LENGTH))); return bytes(out, DIGEST_LENGTH); }
void TLS_PRF(const uint8_t *rtkey, const uint8_t seedArray, uint8_t seedLen, uint8_t dk_len, uint8_t drvkey) { uint32_t length = dk_len * 2;
assert(length <= (0xFF * DIGEST_LENGTH));
uint8_t blockNum;
blockNum = length / DIGEST_LENGTH;
if(length % DIGEST_LENGTH > 0)
blockNum += 1;
uint8_t* okm = new uint8_t[blockNum * DIGEST_LENGTH];
memset(okm, 0, blockNum * DIGEST_LENGTH);
bytes seed(seedArray, seedLen);
bytes block(seedArray, seedLen);
bytes output_block;
for(int i = 0; i < blockNum; ++i)
{
block = HmacArray(rtkey, block);
output_block = HmacArray(rtkey, block + seed);
memcpy(&okm[i * DIGEST_LENGTH], output_block.value(), DIGEST_LENGTH);
}
for(int i = 0; i < dk_len; ++i)
{
drvkey[i] = okm[i] ^ okm[i + dk_len];
}
delete[] okm;
}
void DigestArray(const uint8_t data, uint32_t len, uint8_t out) { SHA256 sha256; ArraySource(data, len, true, new HashFilter(sha256, new ArraySink(out, DIGEST_LENGTH))); }
void RandomArray(const uint8_t* seed, uint8_t seedLen, uint8_t* out, uint8_t len) { RandomPool rng; rng.IncorporateEntropy(seed, seedLen); rng.GenerateBlock(out, len); }
//crypt.h================================================================================================================
void SetByteArray(const char* key, uint8_t* buf, int len); void AES_CTR(const uint8_t *key, const uint8_t *iv, uint8_t ivlen, uint8_t *in, uint8_t *out, uint32_t buflen); void TLS_PRF(const uint8_t *rtkey, const uint8_t seedArray, uint8_t seedLen, uint8_t length, uint8_t drvkey); void DigestArray(const uint8_t data, uint32_t len, uint8_t out); void RandomArray(const uint8_t seed, uint8_t seedLen, uint8_t out, uint8_t len);
//fctpack.cpp================================================================================================================
#include "common.h"
fctpack::fctpack() { fixArea.addChild(&part1); fixArea.addChild(&offset); encryptArea.addChild(&fixArea); encryptArea.addChild(&part2); addChild(&encryptIV); addChild(&encryptArea); }
fctpack::fctpack(Element* elem): fctpack() { if( FindAttribute(elem, "offsetLoc") ) { offsetLoc = hex2int(FindAttribute(elem, "offsetLoc")->Value(), 8); part1.set(offsetLoc); }
const char* n = findElement(elem, "file")->GetText();
FILE* fp = fopen(n, "rb");
if( fp == nullptr )
{
cout << n << " open error. " << endl;
}
random();
fixArea.read(fp);
part2.set(offset - fixArea.gsize());
part2.read(fp);
if(IsEncrypt)
encryptArea.encrypt(encKey, encryptIV, IVLen);
fclose(fp);
}
fctpack::fctpack(Element* elem, FILE* fp): fctpack() { if( elem != nullptr ) { if( FindAttribute(elem, "offsetLoc") ) { offsetLoc = hex2int(FindAttribute(elem, "offsetLoc")->Value(), 8); part1.set(offsetLoc); } }
encryptIV.read(fp);
fixArea.readcipher(fp);
fixArea.decrypt(decKey, encryptIV, IVLen);
part2.set(offset - fixArea.gsize());
part2.readcipher(fp);
encryptArea.decrypt(decKey, encryptIV, IVLen);
if( toolType == EIET && IsEncrypt )
encryptArea.encrypt(encKey, encryptIV, IVLen);
else if( toolType == EIDT )
clearcipher();
}
void fctpack::random() { generateIV(encryptIV.value, IVLen); }
//header.cpp=======================================================================================================================
#include "common.h"
header::header(): Tnode((char*)"header") { plainArea.addChild(&deriveParam); plainArea.addChild(&headerIV);
signandfixArea.addChild(&reserved0);
signandfixArea.addChild(&packageSize);
signandfixArea.addChild(&headerLength);
signandfixArea.addChild(&version);
signandfixArea.addChild(&moduleCount);
sigandvarArea.addChild(&moduleinfos);
sigandvarArea.addChild(&enryptionIV);
nosignArea.addChild(&reserved);
nosignArea.addChild(&signature);
signArea.moveChild(plainArea);
signArea.moveChild(signandfixArea);
signArea.moveChild(sigandvarArea);
encryptArea.moveChild(signandfixArea);
encryptArea.moveChild(sigandvarArea);
encryptArea.moveChild(nosignArea);
fixArea.moveChild(plainArea);
fixArea.moveChild(signandfixArea);
moveChild(plainArea);
moveChild(signandfixArea);
moveChild(sigandvarArea);
moveChild(nosignArea);
}
void header::set(void) { packageSize = moduleinfo::offAccum + HeaderLength + SigLen; headerLength = moduleCount * 0x30 + 0x60 + IVLen; if(HeaderLength > headerLength + SigLen) reserved.set(HeaderLength - headerLength - SigLen); }
void header::set(Element* elem) { elem = findElement(elem, "header"); version = version2Int(FindAttribute(elem, "version")->Value(), 4); }
void header::read(FILE* fp) { uint32_t cursor = ftell(fp); fixArea.read(fp); for( uint32_t i = 0; i < moduleCount; ++i ) moduleinfos.addChild(new moduleinfo(fp)); if(HeaderLength > headerLength + SigLen) reserved.set(HeaderLength - headerLength - SigLen); fseek(fp, cursor, SEEK_SET); Tnode::read(fp); }
void header::readcipher(FILE* fp) { plainArea.read(fp); uint32_t cursor = ftell(fp); signandfixArea.readcipher(fp); if( rootKey ) TLS_PRF(rootKey, deriveParam.value, SeedLen, EncKeyLen, deriveKey); signandfixArea.decrypt(decKey, headerIV, IVLen); for( uint32_t i = 0; i < moduleCount; ++i ) moduleinfos.addChild(new moduleinfo(fp)); if(HeaderLength > headerLength + SigLen) reserved.set(HeaderLength - headerLength - SigLen); fseek(fp, cursor, SEEK_SET); encryptArea.readcipher(fp); }
void header::random(void) { generateIV(headerIV.value, IVLen); generateIV(enryptionIV.value, IVLen); generateIV(deriveParam.value, SeedLen); }
//image.cpp============================================================================================================ #include "common.h"
image::image() { addChild(&head); addChild(&blocks); addChild(&tail); }
image::image(Element* elem): image() { elem = findElement(elem, "image"); if( elem == nullptr ) return; getParams(elem);
FILE* fp;
if( FindAttribute(elem, "headerSize") )
headerSize = hex2int(FindAttribute(elem, "headerSize")->Value(), 8);
if( FindAttribute(elem, "flashSize") )
flashSize = hex2int(FindAttribute(elem, "flashSize")->Value(), 8);
if( findElement(elem, "OTA") )
{
const char* OTApackagePath = findElement(elem, "package")->GetText();
fp = fopen(OTApackagePath, "rb");
if( fp == nullptr )
{
cout << OTApackagePath << " open error. " << endl;
}
OTApackage = new package(elem, fp);
fclose(fp);
}
if( findElement(elem, "FCT") )
{
FCTpackage = new fctpack(findElement(elem, "FCT"));
}
elem = findElement(elem, "block");
list<Element*> blockList = makeList(elem, "block");
for(Element* i: blockList)
blocks.addChild(new block(i, this));
head.set(headerSize);
if( flashSize > gsize() )
tail.set(flashSize - gsize());
}
image::image(Element* elem, FILE* fp): image() { elem = findElement(elem, "image"); if( elem == nullptr ) return; getParams(elem);
if( FindAttribute(elem, "headerSize") )
headerSize = hex2int(FindAttribute(elem, "headerSize")->Value(), 8);
if( FindAttribute(elem, "flashSize") )
flashSize = hex2int(FindAttribute(elem, "flashSize")->Value(), 8);
head.set(headerSize);
head.read(fp);
elem = findElement(elem, "block");
list<Element*> blockList = makeList(elem, "block");
for(Element* i: blockList)
blocks.addChild(new block(i, this, fp));
if( flashSize > gsize() )
tail.set(flashSize - gsize());
tail.read(fp);
}
//main.cpp=====================================================================================================================
#define MAIN
#include "common.h" #include "version.h"
#ifdef TEST extern const char* ftest; #endif
int main(int argc, char* argv[]) { tinyxml2::XMLDocument doc; Tnode* img; const char* configFile = nullptr; const char* inFile = nullptr; const char* outFile = nullptr; FILE* fp;
cout << "OPGT version "
<< ((OPGT_VERSION & 0xFF000000) >> 24 )
<< "."
<< ((OPGT_VERSION & 0x00FF0000) >> 16 )
<< "."
<< ((OPGT_VERSION & 0x0000FF00) >> 8 )
<< "."
<< ((OPGT_VERSION & 0x000000FF) >> 0 )
<< endl;
if(argc <= 1)
{
cout << "No config file and output file. " << endl;
return -1;
}
if(argc > 1)
toolType = getToolType(argv[1]);
if(argc > 2)
configFile = argv[2];
if(argc > 3)
outFile = argv[3];
if(argc > 4)
inFile = argv[4];
if(configFile != nullptr)
{
if( access(configFile, F_OK) != 0 )
{
cout << configFile << " not found. " << endl;
return -1;
}
doc.LoadFile( configFile );
Element* elem = doc.LastChildElement();
if(elem == nullptr)
{
cout << "Config info not found. " << endl;
return -1;
}
if( inFile != nullptr )
{
fp = fopen(inFile, "rb");
if( toolType == OPDT )
img = new package(elem, fp);
else if( toolType == EIET )
img = new image(elem, fp);
else if( toolType == EIDT )
img = new image(elem, fp);
fclose(fp);
}
else
{
if( toolType == OPGT )
img = new package(elem);
else if( toolType == EIGT )
img = new image(elem);
else if( toolType == PDGT )
img = new provdata(elem);
}
#ifdef TEST remove(ftest); #endif // TEST
if( outFile == nullptr )
return -1;
fp = fopen(outFile, "wb");
img->write(fp);
fclose(fp);
cout << "Output done. " << endl;
beforeExit();
return 0;
}
return -1;
}
//module.cpp=============================================================================================================================
#include "common.h"
file::file() { addChild(&padding); }
file::file(const char* n, uint32_t s): file() { if( n == nullptr ) return; name = n; FILE* fp = fopen(name, "rb"); if( fp == nullptr ) { cout << name << " open error. " << endl; beforeExit(); throw; } set(fp); fclose(fp); if(s == 0) { if(size % 16 != 0) padding.set(16 - size % 16); } else { padding.set(s - size); } }
module::module(): Tnode((char*)"module") { addChild(&files); #ifdef SIGNMODULE addChild(&signature); #endif }
module::module(Element* elem): module() { elem = findElement(elem, "module"); if( elem == nullptr ) return;
elem = findElement(elem, "file");
list<Element*> filelist = makeList(elem, "file");
for(Element* i: filelist)
files.addChild(new file(i->GetText()));
#ifdef SIGNMODULE files.sign(signature); #endif }
module::module(moduleinfo& mod, FILE* fp): module() { uint32_t s = mod.moduleSize; files.set(s); if( s % 16 > 0 ) padding.set(16 - 16 % s); if( toolType == EIGT || toolType == EIET || toolType == EIDT || toolType == OPDT ) readcipher(fp); }
//moduleinfo.cpp=============================================================================================================
#include "common.h"
uint32_t moduleinfo::offAccum = 0;
moduleinfo::moduleinfo(): Tnode((char*)"moduleinfo") { addChild(&owner); addChild(&type); addChild(&productID); addChild(&HWversion); addChild(&version); addChild(&offset); addChild(&moduleSize); addChild(&destAddr); addChild(&reserved); }
moduleinfo::moduleinfo(Element* elem): moduleinfo() { moduleSize = 0; FILE* fp; list<Element*> filelist; elem = findElement(elem, "module"); if( elem == nullptr ) return;
owner = FindAttribute(elem, "owner") ->IntValue();
type = FindAttribute(elem, "type") ->IntValue();
productID = FindAttribute(elem, "productID")->IntValue();
HWversion = FindAttribute(elem, "HWversion")->IntValue();
version = version2Int(FindAttribute(elem, "version")->Value(), 4);
destAddr = destAddrTable[owner-1][type-1];
elem = findElement(elem, "file");
filelist = makeList(elem, "file");
uint32_t fileSize;
for(Element* i: filelist)
{
fp = fopen(i->GetText(), "rb");
fileSize = filelength(fileno(fp));
if( fileSize % 16 > 0 )
fileSize += 16 - fileSize % 16;
moduleSize = moduleSize + fileSize;
fclose(fp);
}
offset = offAccum;
offAccum += moduleSize;
}
moduleinfo::moduleinfo(FILE* fp): moduleinfo() { if( toolType == EIGT || toolType == EIET || toolType == EIDT || toolType == OPDT ) { readcipher(fp); } }
//package.cpp====================================================================================================
#include "common.h"
package::package() { addChild(&header); addChild(&modules); addChild(&signature); signArea.addChild(&header); signArea.addChild(&modules); encryptArea.addChild(&modules); encryptArea.addChild(&signature); }
package::package(Element* elem): package() { elem = findElement(elem, "package"); if( elem == nullptr ) return; getParams(elem);
header.set(elem);
moduleinfo::offAccum = 0;
elem = findElement(elem, "module");
list<Element*> modulelist = makeList(elem, "module");
for(Element* i: modulelist)
{
header.moduleinfos.addChild(new moduleinfo(i));
modules.addChild(new module(i));
header.moduleCount = header.moduleCount + 1;
}
header.set();
header.random();
if( rootKey )
TLS_PRF(rootKey, header.deriveParam.value, SeedLen, EncKeyLen, deriveKey);
header.signArea.sign(header.signature);
signArea.sign(signature);
if(IsEncrypt)
{
header.encryptArea.encrypt(encKey, header.headerIV, IVLen);
encryptArea.encrypt(encKey, header.enryptionIV, IVLen);
}
}
package::package(Element* elem, FILE* fp): package() { if(elem != nullptr) { elem = findElement(elem, "package"); if( elem == nullptr ) return; getParams(elem); }
if( rootKey )
TLS_PRF(rootKey, header.deriveParam.value, SeedLen, EncKeyLen, deriveKey);
header.readcipher(fp);
header.encryptArea.decrypt(decKey, header.headerIV, IVLen);
header.signArea.verify(header.signature);
for(Tnode* i: header.moduleinfos.children)
modules.addChild(new module((*(moduleinfo*)i), fp));
signature.readcipher(fp);
encryptArea.decrypt(decKey, header.enryptionIV, IVLen);
#ifdef SIGNMODULE for(Tnode* i: modules.children) ((module*)i)->files.verify(((module*)i)->signature); #endif signArea.verify(signature);
if( toolType == EIET && IsEncrypt )
{
header.encryptArea.encrypt(encKey, header.headerIV, IVLen);
encryptArea.encrypt(encKey, header.enryptionIV, IVLen);
}
else if( toolType == OPDT || toolType == EIDT )
{
clearcipher();
}
}
//provdata.cpp=======================================================================================================================
#include "common.h"
provdata::provdata() { hashArea.addChild(&provMagic); hashArea.addChild(&provDataVersion); hashArea.addChild(&eccCapacity); hashArea.addChild(&productType); hashArea.addChild(&signPublicKey); hashArea.addChild(&latchKey); hashArea.addChild(&ioProtectKey); hashArea.addChild(&encryptedWriteKey); hashArea.addChild(&encryptedReadKey); hashArea.addChild(&rootKey); hashArea.addChild(&deviceKey); hashArea.addChild(&MAC); hashArea.addChild(&serialNumber); hashArea.addChild(&reserved); encryptArea.addChild(&hashArea); encryptArea.addChild(&hashData); addChild(&encryptArea); addChild(&nonce); }
provdata::provdata(Element* elem): provdata() { const char* provDataFileName = findElement(elem, "ProvDataFile")->GetText(); FILE* fp = fopen(provDataFileName, "rb"); if( fp == nullptr ) { cout << "Prov data file open error. " << endl; throw; } read(fp); fclose(fp); if( provIsEncrypt() ) { FILE* fp = fopen(findElement(elem, "ProvDataFile")->GetText(), "rb"); if( fp == nullptr ) { cout << "Prov data file open error. " << endl; throw; } encryptArea.readcipher(fp); nonce.read(fp); fclose(fp);
const char* provKey = "1234567812345678";
encryptArea.decrypt((uint8_t*)provKey, nonce, IVLen);
}
if( hashArea.verifyDigest(hashData) == false )
{
cout << "Prov data file verify fail. " << endl;
throw;
}
}
bool provdata::provIsEncrypt() { for( uint32_t i = 0; i < nonce.size; ++i ) { if( nonce.value[i] != 0 ) return true; } return false; }
//tinyxml2.h================================================================================================
/* Original code by Lee Thomason (www.grinninglizard.com)
This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
-
The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
-
Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
-
This notice may not be removed or altered from any source distribution. */
#ifndef TINYXML2_INCLUDED #define TINYXML2_INCLUDED
#if defined(ANDROID_NDK) || defined(BORLANDC) || defined(QNXNTO)
#else
#endif #include <stdint.h>
/* TODO: intern strings instead of allocation. / / gcc: g++ -Wall -DTINYXML2_DEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe
Formatting, Artistic Style:
AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h
*/
#if defined( _DEBUG ) || defined (DEBUG)
#endif
#ifdef _MSC_VER
#endif
#ifdef _WIN32
#elif GNUC >= 4
#else
#endif
#if defined(TINYXML2_DEBUG)
define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", FILE, LINE ); }
#else
#endif
/* Versioning, past 1.0.14: http://semver.org/ */ static const int TIXML2_MAJOR_VERSION = 7; static const int TIXML2_MINOR_VERSION = 0; static const int TIXML2_PATCH_VERSION = 1;
#define TINYXML2_MAJOR_VERSION 7 #define TINYXML2_MINOR_VERSION 0 #define TINYXML2_PATCH_VERSION 1
// A fixed element depth limit is problematic. There needs to be a // limit to avoid a stack overflow. However, that limit varies per // system, and the capacity of the stack. On the other hand, it's a trivial // attack that can result from ill, malicious, or even correctly formed XML, // so there needs to be a limit in place. static const int TINYXML2_MAX_ELEMENT_DEPTH = 100;
namespace tinyxml2 { class XMLDocument; class XMLElement; class XMLAttribute; class XMLComment; class XMLText; class XMLDeclaration; class XMLUnknown; class XMLPrinter;
/* A class that wraps strings. Normally stores the start and end pointers into the XML file itself, and will apply normalization and entity translation if actually read. Can also store (and memory manage) a traditional char[]
Isn't clear why TINYXML2_LIB is needed; but seems to fix #719
*/ class TINYXML2_LIB StrPair { public: enum { NEEDS_ENTITY_PROCESSING = 0x01, NEEDS_NEWLINE_NORMALIZATION = 0x02, NEEDS_WHITESPACE_COLLAPSING = 0x04,
TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
ATTRIBUTE_NAME = 0,
ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
COMMENT = NEEDS_NEWLINE_NORMALIZATION
};
StrPair() : _flags( 0 ), _start( 0 ), _end( 0 ) {}
~StrPair();
void Set( char* start, char* end, int flags ) {
TIXMLASSERT( start );
TIXMLASSERT( end );
Reset();
_start = start;
_end = end;
_flags = flags | NEEDS_FLUSH;
}
const char* GetStr();
bool Empty() const {
return _start == _end;
}
void SetInternedStr( const char* str ) {
Reset();
_start = const_cast<char*>(str);
}
void SetStr( const char* str, int flags=0 );
char* ParseText( char* in, const char* endTag, int strFlags, int* curLineNumPtr );
char* ParseName( char* in );
void TransferTo( StrPair* other );
void Reset();
private: void CollapseWhitespace();
enum {
NEEDS_FLUSH = 0x100,
NEEDS_DELETE = 0x200
};
int _flags;
char* _start;
char* _end;
StrPair( const StrPair& other ); // not supported
void operator=( const StrPair& other ); // not supported, use TransferTo()
};
/* A dynamic array of Plain Old Data. Doesn't support constructors, etc. Has a small initial memory pool, so that low or no usage will not cause a call to new/delete */ template <class T, int INITIAL_SIZE> class DynArray { public: DynArray() : _mem( _pool ), _allocated( INITIAL_SIZE ), _size( 0 ) { }
~DynArray() {
if ( _mem != _pool ) {
delete [] _mem;
}
}
void Clear() {
_size = 0;
}
void Push( T t ) {
TIXMLASSERT( _size < INT_MAX );
EnsureCapacity( _size+1 );
_mem[_size] = t;
++_size;
}
T* PushArr( int count ) {
TIXMLASSERT( count >= 0 );
TIXMLASSERT( _size <= INT_MAX - count );
EnsureCapacity( _size+count );
T* ret = &_mem[_size];
_size += count;
return ret;
}
T Pop() {
TIXMLASSERT( _size > 0 );
--_size;
return _mem[_size];
}
void PopArr( int count ) {
TIXMLASSERT( _size >= count );
_size -= count;
}
bool Empty() const {
return _size == 0;
}
T& operator[](int i) {
TIXMLASSERT( i>= 0 && i < _size );
return _mem[i];
}
const T& operator[](int i) const {
TIXMLASSERT( i>= 0 && i < _size );
return _mem[i];
}
const T& PeekTop() const {
TIXMLASSERT( _size > 0 );
return _mem[ _size - 1];
}
int Size() const {
TIXMLASSERT( _size >= 0 );
return _size;
}
int Capacity() const {
TIXMLASSERT( _allocated >= INITIAL_SIZE );
return _allocated;
}
void SwapRemove(int i) {
TIXMLASSERT(i >= 0 && i < _size);
TIXMLASSERT(_size > 0);
_mem[i] = _mem[_size - 1];
--_size;
}
const T* Mem() const {
TIXMLASSERT( _mem );
return _mem;
}
T* Mem() {
TIXMLASSERT( _mem );
return _mem;
}
private: DynArray( const DynArray& ); // not supported void operator=( const DynArray& ); // not supported
void EnsureCapacity( int cap ) {
TIXMLASSERT( cap > 0 );
if ( cap > _allocated ) {
TIXMLASSERT( cap <= INT_MAX / 2 );
const int newAllocated = cap * 2;
T* newMem = new T[newAllocated];
TIXMLASSERT( newAllocated >= _size );
memcpy( newMem, _mem, sizeof(T)*_size ); // warning: not using constructors, only works for PODs
if ( _mem != _pool ) {
delete [] _mem;
}
_mem = newMem;
_allocated = newAllocated;
}
}
T* _mem;
T _pool[INITIAL_SIZE];
int _allocated; // objects allocated
int _size; // number objects in use
};
/* Parent virtual class of a pool for fast allocation and deallocation of objects. */ class MemPool { public: MemPool() {} virtual ~MemPool() {}
virtual int ItemSize() const = 0;
virtual void* Alloc() = 0;
virtual void Free( void* ) = 0;
virtual void SetTracked() = 0;
};
/* Template child class to create pools of the correct type. */ template< int ITEM_SIZE > class MemPoolT : public MemPool { public: MemPoolT() : _blockPtrs(), _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0) {} ~MemPoolT() { MemPoolT< ITEM_SIZE >::Clear(); }
void Clear() {
// Delete the blocks.
while( !_blockPtrs.Empty()) {
Block* lastBlock = _blockPtrs.Pop();
delete lastBlock;
}
_root = 0;
_currentAllocs = 0;
_nAllocs = 0;
_maxAllocs = 0;
_nUntracked = 0;
}
virtual int ItemSize() const {
return ITEM_SIZE;
}
int CurrentAllocs() const {
return _currentAllocs;
}
virtual void* Alloc() {
if ( !_root ) {
// Need a new block.
Block* block = new Block();
_blockPtrs.Push( block );
Item* blockItems = block->items;
for( int i = 0; i < ITEMS_PER_BLOCK - 1; ++i ) {
blockItems[i].next = &(blockItems[i + 1]);
}
blockItems[ITEMS_PER_BLOCK - 1].next = 0;
_root = blockItems;
}
Item* const result = _root;
TIXMLASSERT( result != 0 );
_root = _root->next;
++_currentAllocs;
if ( _currentAllocs > _maxAllocs ) {
_maxAllocs = _currentAllocs;
}
++_nAllocs;
++_nUntracked;
return result;
}
virtual void Free( void* mem ) {
if ( !mem ) {
return;
}
--_currentAllocs;
Item* item = static_cast<Item*>( mem );
#ifdef TINYXML2_DEBUG memset( item, 0xfe, sizeof( item ) ); #endif item->next = _root; _root = item; } void Trace( const char name ) { printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n", name, _maxAllocs, _maxAllocs * ITEM_SIZE / 1024, _currentAllocs, ITEM_SIZE, _nAllocs, _blockPtrs.Size() ); }
void SetTracked() {
--_nUntracked;
}
int Untracked() const {
return _nUntracked;
}
// This number is perf sensitive. 4k seems like a good tradeoff on my machine.
// The test file is large, 170k.
// Release: VS2010 gcc(no opt)
// 1k: 4000
// 2k: 4000
// 4k: 3900 21000
// 16k: 5200
// 32k: 4300
// 64k: 4000 21000
// Declared public because some compilers do not accept to use ITEMS_PER_BLOCK
// in private part if ITEMS_PER_BLOCK is private
enum { ITEMS_PER_BLOCK = (4 * 1024) / ITEM_SIZE };
private: MemPoolT( const MemPoolT& ); // not supported void operator=( const MemPoolT& ); // not supported
union Item {
Item* next;
char itemData[ITEM_SIZE];
};
struct Block {
Item items[ITEMS_PER_BLOCK];
};
DynArray< Block*, 10 > _blockPtrs;
Item* _root;
int _currentAllocs;
int _nAllocs;
int _maxAllocs;
int _nUntracked;
};
/** Implements the interface to the "Visitor pattern" (see the Accept() method.) If you call the Accept() method, it requires being passed a XMLVisitor class to handle callbacks. For nodes that contain other nodes (Document, Element) you will get called with a VisitEnter/VisitExit pair. Nodes that are always leafs are simply called with Visit().
If you return 'true' from a Visit method, recursive parsing will continue. If you return
false, <b>no children of this node or its siblings</b> will be visited.
All flavors of Visit methods have a default implementation that returns 'true' (continue
visiting). You need to only override methods that are interesting to you.
Generally Accept() is called on the XMLDocument, although all nodes support visiting.
You should never change the document from a callback.
@sa XMLNode::Accept()
*/ class TINYXML2_LIB XMLVisitor { public: virtual ~XMLVisitor() {}
/// Visit a document.
virtual bool VisitEnter( const XMLDocument& /*doc*/ ) {
return true;
}
/// Visit a document.
virtual bool VisitExit( const XMLDocument& /*doc*/ ) {
return true;
}
/// Visit an element.
virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) {
return true;
}
/// Visit an element.
virtual bool VisitExit( const XMLElement& /*element*/ ) {
return true;
}
/// Visit a declaration.
virtual bool Visit( const XMLDeclaration& /*declaration*/ ) {
return true;
}
/// Visit a text node.
virtual bool Visit( const XMLText& /*text*/ ) {
return true;
}
/// Visit a comment node.
virtual bool Visit( const XMLComment& /*comment*/ ) {
return true;
}
/// Visit an unknown node.
virtual bool Visit( const XMLUnknown& /*unknown*/ ) {
return true;
}
};
// WARNING: must match XMLDocument::_errorNames[] enum XMLError { XML_SUCCESS = 0, XML_NO_ATTRIBUTE, XML_WRONG_ATTRIBUTE_TYPE, XML_ERROR_FILE_NOT_FOUND, XML_ERROR_FILE_COULD_NOT_BE_OPENED, XML_ERROR_FILE_READ_ERROR, XML_ERROR_PARSING_ELEMENT, XML_ERROR_PARSING_ATTRIBUTE, XML_ERROR_PARSING_TEXT, XML_ERROR_PARSING_CDATA, XML_ERROR_PARSING_COMMENT, XML_ERROR_PARSING_DECLARATION, XML_ERROR_PARSING_UNKNOWN, XML_ERROR_EMPTY_DOCUMENT, XML_ERROR_MISMATCHED_ELEMENT, XML_ERROR_PARSING, XML_CAN_NOT_CONVERT_TEXT, XML_NO_TEXT_NODE, XML_ELEMENT_DEPTH_EXCEEDED,
XML_ERROR_COUNT
};
/* Utility functionality. / class TINYXML2_LIB XMLUtil { public: static const char SkipWhiteSpace( const char* p, int* curLineNumPtr ) { TIXMLASSERT( p );
while( IsWhiteSpace(*p) ) {
if (curLineNumPtr && *p == '\n') {
++(*curLineNumPtr);
}
++p;
}
TIXMLASSERT( p );
return p;
}
static char* SkipWhiteSpace( char* p, int* curLineNumPtr ) {
return const_cast<char*>( SkipWhiteSpace( const_cast<const char*>(p), curLineNumPtr ) );
}
// Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't
// correct, but simple, and usually works.
static bool IsWhiteSpace( char p ) {
return !IsUTF8Continuation(p) && isspace( static_cast<unsigned char>(p) );
}
inline static bool IsNameStartChar( unsigned char ch ) {
if ( ch >= 128 ) {
// This is a heuristic guess in attempt to not implement Unicode-aware isalpha()
return true;
}
if ( isalpha( ch ) ) {
return true;
}
return ch == ':' || ch == '_';
}
inline static bool IsNameChar( unsigned char ch ) {
return IsNameStartChar( ch )
|| isdigit( ch )
|| ch == '.'
|| ch == '-';
}
inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) {
if ( p == q ) {
return true;
}
TIXMLASSERT( p );
TIXMLASSERT( q );
TIXMLASSERT( nChar >= 0 );
return strncmp( p, q, nChar ) == 0;
}
inline static bool IsUTF8Continuation( char p ) {
return ( p & 0x80 ) != 0;
}
static const char* ReadBOM( const char* p, bool* hasBOM );
// p is the starting location,
// the UTF-8 value of the entity will be placed in value, and length filled in.
static const char* GetCharacterRef( const char* p, char* value, int* length );
static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length );
// converts primitive types to strings
static void ToStr( int v, char* buffer, int bufferSize );
static void ToStr( unsigned v, char* buffer, int bufferSize );
static void ToStr( bool v, char* buffer, int bufferSize );
static void ToStr( float v, char* buffer, int bufferSize );
static void ToStr( double v, char* buffer, int bufferSize );
static void ToStr(int64_t v, char* buffer, int bufferSize);
// converts strings to primitive types
static bool ToInt( const char* str, int* value );
static bool ToUnsigned( const char* str, unsigned* value );
static bool ToBool( const char* str, bool* value );
static bool ToFloat( const char* str, float* value );
static bool ToDouble( const char* str, double* value );
static bool ToInt64(const char* str, int64_t* value);
// Changes what is serialized for a boolean value.
// Default to "true" and "false". Shouldn't be changed
// unless you have a special testing or compatibility need.
// Be careful: static, global, & not thread safe.
// Be sure to set static const memory as parameters.
static void SetBoolSerialization(const char* writeTrue, const char* writeFalse);
private: static const char* writeBoolTrue; static const char* writeBoolFalse; };
/** XMLNode is a base class for every object that is in the XML Document Object Model (DOM), except XMLAttributes. Nodes have siblings, a parent, and children which can be navigated. A node is always in a XMLDocument. The type of a XMLNode can be queried, and it can be cast to its more defined type.
A XMLDocument allocates memory for all its Nodes.
When the XMLDocument gets deleted, all its Nodes
will also be deleted.
@verbatim
A Document can contain: Element (container or leaf)
Comment (leaf)
Unknown (leaf)
Declaration( leaf )
An Element can contain: Element (container or leaf)
Text (leaf)
Attributes (not on tree)
Comment (leaf)
Unknown (leaf)
@endverbatim
*/ class TINYXML2_LIB XMLNode { friend class XMLDocument; friend class XMLElement; public:
/// Get the XMLDocument that owns this XMLNode.
const XMLDocument* GetDocument() const {
TIXMLASSERT( _document );
return _document;
}
/// Get the XMLDocument that owns this XMLNode.
XMLDocument* GetDocument() {
TIXMLASSERT( _document );
return _document;
}
/// Safely cast to an Element, or null.
virtual XMLElement* ToElement() {
return 0;
}
/// Safely cast to Text, or null.
virtual XMLText* ToText() {
return 0;
}
/// Safely cast to a Comment, or null.
virtual XMLComment* ToComment() {
return 0;
}
/// Safely cast to a Document, or null.
virtual XMLDocument* ToDocument() {
return 0;
}
/// Safely cast to a Declaration, or null.
virtual XMLDeclaration* ToDeclaration() {
return 0;
}
/// Safely cast to an Unknown, or null.
virtual XMLUnknown* ToUnknown() {
return 0;
}
virtual const XMLElement* ToElement() const {
return 0;
}
virtual const XMLText* ToText() const {
return 0;
}
virtual const XMLComment* ToComment() const {
return 0;
}
virtual const XMLDocument* ToDocument() const {
return 0;
}
virtual const XMLDeclaration* ToDeclaration() const {
return 0;
}
virtual const XMLUnknown* ToUnknown() const {
return 0;
}
/** The meaning of 'value' changes for the specific type.
@verbatim
Document: empty (NULL is returned, not an empty string)
Element: name of the element
Comment: the comment text
Unknown: the tag contents
Text: the text string
@endverbatim
*/
const char* Value() const;
/** Set the Value of an XML node.
@sa Value()
*/
void SetValue( const char* val, bool staticMem=false );
/// Gets the line number the node is in, if the document was parsed from a file.
int GetLineNum() const { return _parseLineNum; }
/// Get the parent of this node on the DOM.
const XMLNode* Parent() const {
return _parent;
}
XMLNode* Parent() {
return _parent;
}
/// Returns true if this node has no children.
bool NoChildren() const {
return !_firstChild;
}
/// Get the first child node, or null if none exists.
const XMLNode* FirstChild() const {
return _firstChild;
}
XMLNode* FirstChild() {
return _firstChild;
}
/** Get the first child element, or optionally the first child
element with the specified name.
*/
const XMLElement* FirstChildElement( const char* name = 0 ) const;
XMLElement* FirstChildElement( const char* name = 0 ) {
return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( name ));
}
/// Get the last child node, or null if none exists.
const XMLNode* LastChild() const {
return _lastChild;
}
XMLNode* LastChild() {
return _lastChild;
}
/** Get the last child element or optionally the last child
element with the specified name.
*/
const XMLElement* LastChildElement( const char* name = 0 ) const;
XMLElement* LastChildElement( const char* name = 0 ) {
return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(name) );
}
/// Get the previous (left) sibling node of this node.
const XMLNode* PreviousSibling() const {
return _prev;
}
XMLNode* PreviousSibling() {
return _prev;
}
/// Get the previous (left) sibling element of this node, with an optionally supplied name.
const XMLElement* PreviousSiblingElement( const char* name = 0 ) const ;
XMLElement* PreviousSiblingElement( const char* name = 0 ) {
return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( name ) );
}
/// Get the next (right) sibling node of this node.
const XMLNode* NextSibling() const {
return _next;
}
XMLNode* NextSibling() {
return _next;
}
/// Get the next (right) sibling element of this node, with an optionally supplied name.
const XMLElement* NextSiblingElement( const char* name = 0 ) const;
XMLElement* NextSiblingElement( const char* name = 0 ) {
return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->NextSiblingElement( name ) );
}
/**
Add a child node as the last (right) child.
If the child node is already part of the document,
it is moved from its old location to the new location.
Returns the addThis argument or 0 if the node does not
belong to the same document.
*/
XMLNode* InsertEndChild( XMLNode* addThis );
XMLNode* LinkEndChild( XMLNode* addThis ) {
return InsertEndChild( addThis );
}
/**
Add a child node as the first (left) child.
If the child node is already part of the document,
it is moved from its old location to the new location.
Returns the addThis argument or 0 if the node does not
belong to the same document.
*/
XMLNode* InsertFirstChild( XMLNode* addThis );
/**
Add a node after the specified child node.
If the child node is already part of the document,
it is moved from its old location to the new location.
Returns the addThis argument or 0 if the afterThis node
is not a child of this node, or if the node does not
belong to the same document.
*/
XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis );
/**
Delete all the children of this node.
*/
void DeleteChildren();
/**
Delete a child of this node.
*/
void DeleteChild( XMLNode* node );
/**
Make a copy of this node, but not its children.
You may pass in a Document pointer that will be
the owner of the new Node. If the 'document' is
null, then the node returned will be allocated
from the current Document. (this->GetDocument())
Note: if called on a XMLDocument, this will return null.
*/
virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0;
/**
Make a copy of this node and all its children.
If the 'target' is null, then the nodes will
be allocated in the current document. If 'target'
is specified, the memory will be allocated is the
specified XMLDocument.
NOTE: This is probably not the correct tool to
copy a document, since XMLDocuments can have multiple
top level XMLNodes. You probably want to use
XMLDocument::DeepCopy()
*/
XMLNode* DeepClone( XMLDocument* target ) const;
/**
Test if 2 nodes are the same, but don't test children.
The 2 nodes do not need to be in the same Document.
Note: if called on a XMLDocument, this will return false.
*/
virtual bool ShallowEqual( const XMLNode* compare ) const = 0;
/** Accept a hierarchical visit of the nodes in the TinyXML-2 DOM. Every node in the
XML tree will be conditionally visited and the host will be called back
via the XMLVisitor interface.
This is essentially a SAX interface for TinyXML-2. (Note however it doesn't re-parse
the XML for the callbacks, so the performance of TinyXML-2 is unchanged by using this
interface versus any other.)
The interface has been based on ideas from:
- http://www.saxproject.org/
- http://c2.com/cgi/wiki?HierarchicalVisitorPattern
Which are both good references for "visiting".
An example of using Accept():
@verbatim
XMLPrinter printer;
tinyxmlDoc.Accept( &printer );
const char* xmlcstr = printer.CStr();
@endverbatim
*/
virtual bool Accept( XMLVisitor* visitor ) const = 0;
/**
Set user data into the XMLNode. TinyXML-2 in
no way processes or interprets user data.
It is initially 0.
*/
void SetUserData(void* userData) { _userData = userData; }
/**
Get user data set into the XMLNode. TinyXML-2 in
no way processes or interprets user data.
It is initially 0.
*/
void* GetUserData() const { return _userData; }
protected: explicit XMLNode( XMLDocument* ); virtual ~XMLNode();
virtual char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr);
XMLDocument* _document;
XMLNode* _parent;
mutable StrPair _value;
int _parseLineNum;
XMLNode* _firstChild;
XMLNode* _lastChild;
XMLNode* _prev;
XMLNode* _next;
void* _userData;
private: MemPool* _memPool; void Unlink( XMLNode* child ); static void DeleteNode( XMLNode* node ); void InsertChildPreamble( XMLNode* insertThis ) const; const XMLElement* ToElementWithName( const char* name ) const;
XMLNode( const XMLNode& ); // not supported
XMLNode& operator=( const XMLNode& ); // not supported
};
/** XML text.
Note that a text node can have child element nodes, for example:
@verbatim
<root>This is <b>bold</b></root>
@endverbatim
A text node can have 2 ways to output the next. "normal" output
and CDATA. It will default to the mode it was parsed from the XML file and
you generally want to leave it alone, but you can change the output mode with
SetCData() and query it with CData().
/ class TINYXML2_LIB XMLText : public XMLNode { friend class XMLDocument; public: virtual bool Accept( XMLVisitor visitor ) const;
virtual XMLText* ToText() {
return this;
}
virtual const XMLText* ToText() const {
return this;
}
/// Declare whether this should be CDATA or standard text.
void SetCData( bool isCData ) {
_isCData = isCData;
}
/// Returns true if this is a CDATA text element.
bool CData() const {
return _isCData;
}
virtual XMLNode* ShallowClone( XMLDocument* document ) const;
virtual bool ShallowEqual( const XMLNode* compare ) const;
protected: explicit XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {} virtual ~XMLText() {}
char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );
private: bool _isCData;
XMLText( const XMLText& ); // not supported
XMLText& operator=( const XMLText& ); // not supported
};
/** An XML Comment. / class TINYXML2_LIB XMLComment : public XMLNode { friend class XMLDocument; public: virtual XMLComment ToComment() { return this; } virtual const XMLComment* ToComment() const { return this; }
virtual bool Accept( XMLVisitor* visitor ) const;
virtual XMLNode* ShallowClone( XMLDocument* document ) const;
virtual bool ShallowEqual( const XMLNode* compare ) const;
protected: explicit XMLComment( XMLDocument* doc ); virtual ~XMLComment();
char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr);
private: XMLComment( const XMLComment& ); // not supported XMLComment& operator=( const XMLComment& ); // not supported };
/** In correct XML the declaration is the first entry in the file. @verbatim @endverbatim
TinyXML-2 will happily read or write files without a declaration,
however.
The text of the declaration isn't interpreted. It is parsed
and written as a string.
/ class TINYXML2_LIB XMLDeclaration : public XMLNode { friend class XMLDocument; public: virtual XMLDeclaration ToDeclaration() { return this; } virtual const XMLDeclaration* ToDeclaration() const { return this; }
virtual bool Accept( XMLVisitor* visitor ) const;
virtual XMLNode* ShallowClone( XMLDocument* document ) const;
virtual bool ShallowEqual( const XMLNode* compare ) const;
protected: explicit XMLDeclaration( XMLDocument* doc ); virtual ~XMLDeclaration();
char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );
private: XMLDeclaration( const XMLDeclaration& ); // not supported XMLDeclaration& operator=( const XMLDeclaration& ); // not supported };
/** Any tag that TinyXML-2 doesn't recognize is saved as an unknown. It is a tag of text, but should not be modified. It will be written back to the XML, unchanged, when the file is saved.
DTD tags get thrown into XMLUnknowns.
/ class TINYXML2_LIB XMLUnknown : public XMLNode { friend class XMLDocument; public: virtual XMLUnknown ToUnknown() { return this; } virtual const XMLUnknown* ToUnknown() const { return this; }
virtual bool Accept( XMLVisitor* visitor ) const;
virtual XMLNode* ShallowClone( XMLDocument* document ) const;
virtual bool ShallowEqual( const XMLNode* compare ) const;
protected: explicit XMLUnknown( XMLDocument* doc ); virtual ~XMLUnknown();
char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );
private: XMLUnknown( const XMLUnknown& ); // not supported XMLUnknown& operator=( const XMLUnknown& ); // not supported };
/** An attribute is a name-value pair. Elements have an arbitrary number of attributes, each with a unique name.
@note The attributes are not XMLNodes. You may only query the
Next() attribute in a list.
/ class TINYXML2_LIB XMLAttribute { friend class XMLElement; public: /// The name of the attribute. const char Name() const;
/// The value of the attribute.
const char* Value() const;
/// Gets the line number the attribute is in, if the document was parsed from a file.
int GetLineNum() const { return _parseLineNum; }
/// The next attribute in the list.
const XMLAttribute* Next() const {
return _next;
}
/** IntValue interprets the attribute as an integer, and returns the value.
If the value isn't an integer, 0 will be returned. There is no error checking;
use QueryIntValue() if you need error checking.
*/
int IntValue() const {
int i = 0;
QueryIntValue(&i);
return i;
}
int64_t Int64Value() const {
int64_t i = 0;
QueryInt64Value(&i);
return i;
}
/// Query as an unsigned integer. See IntValue()
unsigned UnsignedValue() const {
unsigned i=0;
QueryUnsignedValue( &i );
return i;
}
/// Query as a boolean. See IntValue()
bool BoolValue() const {
bool b=false;
QueryBoolValue( &b );
return b;
}
/// Query as a double. See IntValue()
double DoubleValue() const {
double d=0;
QueryDoubleValue( &d );
return d;
}
/// Query as a float. See IntValue()
float FloatValue() const {
float f=0;
QueryFloatValue( &f );
return f;
}
/** QueryIntValue interprets the attribute as an integer, and returns the value
in the provided parameter. The function will return XML_SUCCESS on success,
and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful.
*/
XMLError QueryIntValue( int* value ) const;
/// See QueryIntValue
XMLError QueryUnsignedValue( unsigned int* value ) const;
/// See QueryIntValue
XMLError QueryInt64Value(int64_t* value) const;
/// See QueryIntValue
XMLError QueryBoolValue( bool* value ) const;
/// See QueryIntValue
XMLError QueryDoubleValue( double* value ) const;
/// See QueryIntValue
XMLError QueryFloatValue( float* value ) const;
/// Set the attribute to a string value.
void SetAttribute( const char* value );
/// Set the attribute to value.
void SetAttribute( int value );
/// Set the attribute to value.
void SetAttribute( unsigned value );
/// Set the attribute to value.
void SetAttribute(int64_t value);
/// Set the attribute to value.
void SetAttribute( bool value );
/// Set the attribute to value.
void SetAttribute( double value );
/// Set the attribute to value.
void SetAttribute( float value );
private: enum { BUF_SIZE = 200 };
XMLAttribute() : _name(), _value(),_parseLineNum( 0 ), _next( 0 ), _memPool( 0 ) {}
virtual ~XMLAttribute() {}
XMLAttribute( const XMLAttribute& ); // not supported
void operator=( const XMLAttribute& ); // not supported
void SetName( const char* name );
char* ParseDeep( char* p, bool processEntities, int* curLineNumPtr );
mutable StrPair _name;
mutable StrPair _value;
int _parseLineNum;
XMLAttribute* _next;
MemPool* _memPool;
};
/** The element is a container class. It has a value, the element name, and can contain other elements, text, comments, and unknowns. Elements also contain an arbitrary number of attributes. / class TINYXML2_LIB XMLElement : public XMLNode { friend class XMLDocument; public: /// Get the name of an element (which is the Value() of the node.) const char Name() const { return Value(); } /// Set the name of the element. void SetName( const char* str, bool staticMem=false ) { SetValue( str, staticMem ); }
virtual XMLElement* ToElement() {
return this;
}
virtual const XMLElement* ToElement() const {
return this;
}
virtual bool Accept( XMLVisitor* visitor ) const;
/** Given an attribute name, Attribute() returns the value
for the attribute of that name, or null if none
exists. For example:
@verbatim
const char* value = ele->Attribute( "foo" );
@endverbatim
The 'value' parameter is normally null. However, if specified,
the attribute will only be returned if the 'name' and 'value'
match. This allow you to write code:
@verbatim
if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar();
@endverbatim
rather than:
@verbatim
if ( ele->Attribute( "foo" ) ) {
if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar();
}
@endverbatim
*/
const char* Attribute( const char* name, const char* value=0 ) const;
/** Given an attribute name, IntAttribute() returns the value
of the attribute interpreted as an integer. The default
value will be returned if the attribute isn't present,
or if there is an error. (For a method with error
checking, see QueryIntAttribute()).
*/
int IntAttribute(const char* name, int defaultValue = 0) const;
/// See IntAttribute()
unsigned UnsignedAttribute(const char* name, unsigned defaultValue = 0) const;
/// See IntAttribute()
int64_t Int64Attribute(const char* name, int64_t defaultValue = 0) const;
/// See IntAttribute()
bool BoolAttribute(const char* name, bool defaultValue = false) const;
/// See IntAttribute()
double DoubleAttribute(const char* name, double defaultValue = 0) const;
/// See IntAttribute()
float FloatAttribute(const char* name, float defaultValue = 0) const;
/** Given an attribute name, QueryIntAttribute() returns
XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion
can't be performed, or XML_NO_ATTRIBUTE if the attribute
doesn't exist. If successful, the result of the conversion
will be written to 'value'. If not successful, nothing will
be written to 'value'. This allows you to provide default
value:
@verbatim
int value = 10;
QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10
@endverbatim
*/
XMLError QueryIntAttribute( const char* name, int* value ) const {
const XMLAttribute* a = FindAttribute( name );
if ( !a ) {
return XML_NO_ATTRIBUTE;
}
return a->QueryIntValue( value );
}
/// See QueryIntAttribute()
XMLError QueryUnsignedAttribute( const char* name, unsigned int* value ) const {
const XMLAttribute* a = FindAttribute( name );
if ( !a ) {
return XML_NO_ATTRIBUTE;
}
return a->QueryUnsignedValue( value );
}
/// See QueryIntAttribute()
XMLError QueryInt64Attribute(const char* name, int64_t* value) const {
const XMLAttribute* a = FindAttribute(name);
if (!a) {
return XML_NO_ATTRIBUTE;
}
return a->QueryInt64Value(value);
}
/// See QueryIntAttribute()
XMLError QueryBoolAttribute( const char* name, bool* value ) const {
const XMLAttribute* a = FindAttribute( name );
if ( !a ) {
return XML_NO_ATTRIBUTE;
}
return a->QueryBoolValue( value );
}
/// See QueryIntAttribute()
XMLError QueryDoubleAttribute( const char* name, double* value ) const {
const XMLAttribute* a = FindAttribute( name );
if ( !a ) {
return XML_NO_ATTRIBUTE;
}
return a->QueryDoubleValue( value );
}
/// See QueryIntAttribute()
XMLError QueryFloatAttribute( const char* name, float* value ) const {
const XMLAttribute* a = FindAttribute( name );
if ( !a ) {
return XML_NO_ATTRIBUTE;
}
return a->QueryFloatValue( value );
}
/// See QueryIntAttribute()
XMLError QueryStringAttribute(const char* name, const char** value) const {
const XMLAttribute* a = FindAttribute(name);
if (!a) {
return XML_NO_ATTRIBUTE;
}
*value = a->Value();
return XML_SUCCESS;
}
/** Given an attribute name, QueryAttribute() returns
XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion
can't be performed, or XML_NO_ATTRIBUTE if the attribute
doesn't exist. It is overloaded for the primitive types,
and is a generally more convenient replacement of
QueryIntAttribute() and related functions.
If successful, the result of the conversion
will be written to 'value'. If not successful, nothing will
be written to 'value'. This allows you to provide default
value:
@verbatim
int value = 10;
QueryAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10
@endverbatim
*/
XMLError QueryAttribute( const char* name, int* value ) const {
return QueryIntAttribute( name, value );
}
XMLError QueryAttribute( const char* name, unsigned int* value ) const {
return QueryUnsignedAttribute( name, value );
}
XMLError QueryAttribute(const char* name, int64_t* value) const {
return QueryInt64Attribute(name, value);
}
XMLError QueryAttribute( const char* name, bool* value ) const {
return QueryBoolAttribute( name, value );
}
XMLError QueryAttribute( const char* name, double* value ) const {
return QueryDoubleAttribute( name, value );
}
XMLError QueryAttribute( const char* name, float* value ) const {
return QueryFloatAttribute( name, value );
}
/// Sets the named attribute to value.
void SetAttribute( const char* name, const char* value ) {
XMLAttribute* a = FindOrCreateAttribute( name );
a->SetAttribute( value );
}
/// Sets the named attribute to value.
void SetAttribute( const char* name, int value ) {
XMLAttribute* a = FindOrCreateAttribute( name );
a->SetAttribute( value );
}
/// Sets the named attribute to value.
void SetAttribute( const char* name, unsigned value ) {
XMLAttribute* a = FindOrCreateAttribute( name );
a->SetAttribute( value );
}
/// Sets the named attribute to value.
void SetAttribute(const char* name, int64_t value) {
XMLAttribute* a = FindOrCreateAttribute(name);
a->SetAttribute(value);
}
/// Sets the named attribute to value.
void SetAttribute( const char* name, bool value ) {
XMLAttribute* a = FindOrCreateAttribute( name );
a->SetAttribute( value );
}
/// Sets the named attribute to value.
void SetAttribute( const char* name, double value ) {
XMLAttribute* a = FindOrCreateAttribute( name );
a->SetAttribute( value );
}
/// Sets the named attribute to value.
void SetAttribute( const char* name, float value ) {
XMLAttribute* a = FindOrCreateAttribute( name );
a->SetAttribute( value );
}
/**
Delete an attribute.
*/
void DeleteAttribute( const char* name );
/// Return the first attribute in the list.
const XMLAttribute* FirstAttribute() const {
return _rootAttribute;
}
/// Query a specific attribute in the list.
const XMLAttribute* FindAttribute( const char* name ) const;
/** Convenience function for easy access to the text inside an element. Although easy
and concise, GetText() is limited compared to getting the XMLText child
and accessing it directly.
If the first child of 'this' is a XMLText, the GetText()
returns the character string of the Text node, else null is returned.
This is a convenient method for getting the text of simple contained text:
@verbatim
<foo>This is text</foo>
const char* str = fooElement->GetText();
@endverbatim
'str' will be a pointer to "This is text".
Note that this function can be misleading. If the element foo was created from
this XML:
@verbatim
<foo><b>This is text</b></foo>
@endverbatim
then the value of str would be null. The first child node isn't a text node, it is
another element. From this XML:
@verbatim
<foo>This is <b>text</b></foo>
@endverbatim
GetText() will return "This is ".
*/
const char* GetText() const;
/** Convenience function for easy access to the text inside an element. Although easy
and concise, SetText() is limited compared to creating an XMLText child
and mutating it directly.
If the first child of 'this' is a XMLText, SetText() sets its value to
the given string, otherwise it will create a first child that is an XMLText.
This is a convenient method for setting the text of simple contained text:
@verbatim
<foo>This is text</foo>
fooElement->SetText( "Hullaballoo!" );
<foo>Hullaballoo!</foo>
@endverbatim
Note that this function can be misleading. If the element foo was created from
this XML:
@verbatim
<foo><b>This is text</b></foo>
@endverbatim
then it will not change "This is text", but rather prefix it with a text element:
@verbatim
<foo>Hullaballoo!<b>This is text</b></foo>
@endverbatim
For this XML:
@verbatim
<foo />
@endverbatim
SetText() will generate
@verbatim
<foo>Hullaballoo!</foo>
@endverbatim
*/
void SetText( const char* inText );
/// Convenience method for setting text inside an element. See SetText() for important limitations.
void SetText( int value );
/// Convenience method for setting text inside an element. See SetText() for important limitations.
void SetText( unsigned value );
/// Convenience method for setting text inside an element. See SetText() for important limitations.
void SetText(int64_t value);
/// Convenience method for setting text inside an element. See SetText() for important limitations.
void SetText( bool value );
/// Convenience method for setting text inside an element. See SetText() for important limitations.
void SetText( double value );
/// Convenience method for setting text inside an element. See SetText() for important limitations.
void SetText( float value );
/**
Convenience method to query the value of a child text node. This is probably best
shown by example. Given you have a document is this form:
@verbatim
<point>
<x>1</x>
<y>1.4</y>
</point>
@endverbatim
The QueryIntText() and similar functions provide a safe and easier way to get to the
"value" of x and y.
@verbatim
int x = 0;
float y = 0; // types of x and y are contrived for example
const XMLElement* xElement = pointElement->FirstChildElement( "x" );
const XMLElement* yElement = pointElement->FirstChildElement( "y" );
xElement->QueryIntText( &x );
yElement->QueryFloatText( &y );
@endverbatim
@returns XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted
to the requested type, and XML_NO_TEXT_NODE if there is no child text to query.
*/
XMLError QueryIntText( int* ival ) const;
/// See QueryIntText()
XMLError QueryUnsignedText( unsigned* uval ) const;
/// See QueryIntText()
XMLError QueryInt64Text(int64_t* uval) const;
/// See QueryIntText()
XMLError QueryBoolText( bool* bval ) const;
/// See QueryIntText()
XMLError QueryDoubleText( double* dval ) const;
/// See QueryIntText()
XMLError QueryFloatText( float* fval ) const;
int IntText(int defaultValue = 0) const;
/// See QueryIntText()
unsigned UnsignedText(unsigned defaultValue = 0) const;
/// See QueryIntText()
int64_t Int64Text(int64_t defaultValue = 0) const;
/// See QueryIntText()
bool BoolText(bool defaultValue = false) const;
/// See QueryIntText()
double DoubleText(double defaultValue = 0) const;
/// See QueryIntText()
float FloatText(float defaultValue = 0) const;
// internal:
enum ElementClosingType {
OPEN, // <foo>
CLOSED, // <foo/>
CLOSING // </foo>
};
ElementClosingType ClosingType() const {
return _closingType;
}
virtual XMLNode* ShallowClone( XMLDocument* document ) const;
virtual bool ShallowEqual( const XMLNode* compare ) const;
protected: char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );
private: XMLElement( XMLDocument* doc ); virtual ~XMLElement(); XMLElement( const XMLElement& ); // not supported void operator=( const XMLElement& ); // not supported
XMLAttribute* FindOrCreateAttribute( const char* name );
char* ParseAttributes( char* p, int* curLineNumPtr );
static void DeleteAttribute( XMLAttribute* attribute );
XMLAttribute* CreateAttribute();
enum { BUF_SIZE = 200 };
ElementClosingType _closingType;
// The attribute list is ordered; there is no 'lastAttribute'
// because the list needs to be scanned for dupes before adding
// a new attribute.
XMLAttribute* _rootAttribute;
};
enum Whitespace { PRESERVE_WHITESPACE, COLLAPSE_WHITESPACE };
/** A Document binds together all the functionality. It can be saved, loaded, and printed to the screen. All Nodes are connected and allocated to a Document. If the Document is deleted, all its Nodes are also deleted. */ class TINYXML2_LIB XMLDocument : public XMLNode { friend class XMLElement; // Gives access to SetError and Push/PopDepth, but over-access for everything else. // Wishing C++ had "internal" scope. friend class XMLNode; friend class XMLText; friend class XMLComment; friend class XMLDeclaration; friend class XMLUnknown; public: /// constructor XMLDocument( bool processEntities = true, Whitespace whitespaceMode = PRESERVE_WHITESPACE ); ~XMLDocument();
virtual XMLDocument* ToDocument() {
TIXMLASSERT( this == _document );
return this;
}
virtual const XMLDocument* ToDocument() const {
TIXMLASSERT( this == _document );
return this;
}
/**
Parse an XML file from a character string.
Returns XML_SUCCESS (0) on success, or
an errorID.
You may optionally pass in the 'nBytes', which is
the number of bytes which will be parsed. If not
specified, TinyXML-2 will assume 'xml' points to a
null terminated string.
*/
XMLError Parse( const char* xml, size_t nBytes=(size_t)(-1) );
/**
Load an XML file from disk.
Returns XML_SUCCESS (0) on success, or
an errorID.
*/
XMLError LoadFile( const char* filename );
/**
Load an XML file from disk. You are responsible
for providing and closing the FILE*.
NOTE: The file should be opened as binary ("rb")
not text in order for TinyXML-2 to correctly
do newline normalization.
Returns XML_SUCCESS (0) on success, or
an errorID.
*/
XMLError LoadFile( FILE* );
/**
Save the XML file to disk.
Returns XML_SUCCESS (0) on success, or
an errorID.
*/
XMLError SaveFile( const char* filename, bool compact = false );
/**
Save the XML file to disk. You are responsible
for providing and closing the FILE*.
Returns XML_SUCCESS (0) on success, or
an errorID.
*/
XMLError SaveFile( FILE* fp, bool compact = false );
bool ProcessEntities() const {
return _processEntities;
}
Whitespace WhitespaceMode() const {
return _whitespaceMode;
}
/**
Returns true if this document has a leading Byte Order Mark of UTF8.
*/
bool HasBOM() const {
return _writeBOM;
}
/** Sets whether to write the BOM when writing the file.
*/
void SetBOM( bool useBOM ) {
_writeBOM = useBOM;
}
/** Return the root element of DOM. Equivalent to FirstChildElement().
To get the first node, use FirstChild().
*/
XMLElement* RootElement() {
return FirstChildElement();
}
const XMLElement* RootElement() const {
return FirstChildElement();
}
/** Print the Document. If the Printer is not provided, it will
print to stdout. If you provide Printer, this can print to a file:
@verbatim
XMLPrinter printer( fp );
doc.Print( &printer );
@endverbatim
Or you can use a printer to print to memory:
@verbatim
XMLPrinter printer;
doc.Print( &printer );
// printer.CStr() has a const char* to the XML
@endverbatim
*/
void Print( XMLPrinter* streamer=0 ) const;
virtual bool Accept( XMLVisitor* visitor ) const;
/**
Create a new Element associated with
this Document. The memory for the Element
is managed by the Document.
*/
XMLElement* NewElement( const char* name );
/**
Create a new Comment associated with
this Document. The memory for the Comment
is managed by the Document.
*/
XMLComment* NewComment( const char* comment );
/**
Create a new Text associated with
this Document. The memory for the Text
is managed by the Document.
*/
XMLText* NewText( const char* text );
/**
Create a new Declaration associated with
this Document. The memory for the object
is managed by the Document.
If the 'text' param is null, the standard
declaration is used.:
@verbatim
<?xml version="1.0" encoding="UTF-8"?>
@endverbatim
*/
XMLDeclaration* NewDeclaration( const char* text=0 );
/**
Create a new Unknown associated with
this Document. The memory for the object
is managed by the Document.
*/
XMLUnknown* NewUnknown( const char* text );
/**
Delete a node associated with this document.
It will be unlinked from the DOM.
*/
void DeleteNode( XMLNode* node );
void ClearError() {
SetError(XML_SUCCESS, 0, 0);
}
/// Return true if there was an error parsing the document.
bool Error() const {
return _errorID != XML_SUCCESS;
}
/// Return the errorID.
XMLError ErrorID() const {
return _errorID;
}
const char* ErrorName() const;
static const char* ErrorIDToName(XMLError errorID);
/** Returns a "long form" error description. A hopefully helpful
diagnostic with location, line number, and/or additional info.
*/
const char* ErrorStr() const;
/// A (trivial) utility function that prints the ErrorStr() to stdout.
void PrintError() const;
/// Return the line where the error occurred, or zero if unknown.
int ErrorLineNum() const
{
return _errorLineNum;
}
/// Clear the document, resetting it to the initial state.
void Clear();
/**
Copies this document to a target document.
The target will be completely cleared before the copy.
If you want to copy a sub-tree, see XMLNode::DeepClone().
NOTE: that the 'target' must be non-null.
*/
void DeepCopy(XMLDocument* target) const;
// internal
char* Identify( char* p, XMLNode** node );
// internal
void MarkInUse(XMLNode*);
virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const {
return 0;
}
virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const {
return false;
}
private: XMLDocument( const XMLDocument& ); // not supported void operator=( const XMLDocument& ); // not supported
bool _writeBOM;
bool _processEntities;
XMLError _errorID;
Whitespace _whitespaceMode;
mutable StrPair _errorStr;
int _errorLineNum;
char* _charBuffer;
int _parseCurLineNum;
int _parsingDepth;
// Memory tracking does add some overhead.
// However, the code assumes that you don't
// have a bunch of unlinked nodes around.
// Therefore it takes less memory to track
// in the document vs. a linked list in the XMLNode,
// and the performance is the same.
DynArray<XMLNode*, 10> _unlinked;
MemPoolT< sizeof(XMLElement) > _elementPool;
MemPoolT< sizeof(XMLAttribute) > _attributePool;
MemPoolT< sizeof(XMLText) > _textPool;
MemPoolT< sizeof(XMLComment) > _commentPool;
static const char* _errorNames[XML_ERROR_COUNT];
void Parse();
void SetError( XMLError error, int lineNum, const char* format, ... );
// Something of an obvious security hole, once it was discovered.
// Either an ill-formed XML or an excessively deep one can overflow
// the stack. Track stack depth, and error out if needed.
class DepthTracker {
public:
explicit DepthTracker(XMLDocument * document) {
this->_document = document;
document->PushDepth();
}
~DepthTracker() {
_document->PopDepth();
}
private:
XMLDocument * _document;
};
void PushDepth();
void PopDepth();
template<class NodeType, int PoolElementSize>
NodeType* CreateUnlinkedNode( MemPoolT<PoolElementSize>& pool );
};
template<class NodeType, int PoolElementSize> inline NodeType* XMLDocument::CreateUnlinkedNode( MemPoolT& pool ) { TIXMLASSERT( sizeof( NodeType ) == PoolElementSize ); TIXMLASSERT( sizeof( NodeType ) == pool.ItemSize() ); NodeType* returnNode = new (pool.Alloc()) NodeType( this ); TIXMLASSERT( returnNode ); returnNode->_memPool = &pool;
_unlinked.Push(returnNode);
return returnNode;
}
/** A XMLHandle is a class that wraps a node pointer with null checks; this is an incredibly useful thing. Note that XMLHandle is not part of the TinyXML-2 DOM structure. It is a separate utility class.
Take an example:
@verbatim
<Document>
<Element attributeA = "valueA">
<Child attributeB = "value1" />
<Child attributeB = "value2" />
</Element>
</Document>
@endverbatim
Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very
easy to write a *lot* of code that looks like:
@verbatim
XMLElement* root = document.FirstChildElement( "Document" );
if ( root )
{
XMLElement* element = root->FirstChildElement( "Element" );
if ( element )
{
XMLElement* child = element->FirstChildElement( "Child" );
if ( child )
{
XMLElement* child2 = child->NextSiblingElement( "Child" );
if ( child2 )
{
// Finally do something useful.
@endverbatim
And that doesn't even cover "else" cases. XMLHandle addresses the verbosity
of such code. A XMLHandle checks for null pointers so it is perfectly safe
and correct to use:
@verbatim
XMLHandle docHandle( &document );
XMLElement* child2 = docHandle.FirstChildElement( "Document" ).FirstChildElement( "Element" ).FirstChildElement().NextSiblingElement();
if ( child2 )
{
// do something useful
@endverbatim
Which is MUCH more concise and useful.
It is also safe to copy handles - internally they are nothing more than node pointers.
@verbatim
XMLHandle handleCopy = handle;
@endverbatim
See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects.
/ class TINYXML2_LIB XMLHandle { public: /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. explicit XMLHandle( XMLNode node ) : _node( node ) { } /// Create a handle from a node. explicit XMLHandle( XMLNode& node ) : _node( &node ) { } /// Copy constructor XMLHandle( const XMLHandle& ref ) : _node( ref._node ) { } /// Assignment XMLHandle& operator=( const XMLHandle& ref ) { _node = ref._node; return *this; }
/// Get the first child of this handle.
XMLHandle FirstChild() {
return XMLHandle( _node ? _node->FirstChild() : 0 );
}
/// Get the first child element of this handle.
XMLHandle FirstChildElement( const char* name = 0 ) {
return XMLHandle( _node ? _node->FirstChildElement( name ) : 0 );
}
/// Get the last child of this handle.
XMLHandle LastChild() {
return XMLHandle( _node ? _node->LastChild() : 0 );
}
/// Get the last child element of this handle.
XMLHandle LastChildElement( const char* name = 0 ) {
return XMLHandle( _node ? _node->LastChildElement( name ) : 0 );
}
/// Get the previous sibling of this handle.
XMLHandle PreviousSibling() {
return XMLHandle( _node ? _node->PreviousSibling() : 0 );
}
/// Get the previous sibling element of this handle.
XMLHandle PreviousSiblingElement( const char* name = 0 ) {
return XMLHandle( _node ? _node->PreviousSiblingElement( name ) : 0 );
}
/// Get the next sibling of this handle.
XMLHandle NextSibling() {
return XMLHandle( _node ? _node->NextSibling() : 0 );
}
/// Get the next sibling element of this handle.
XMLHandle NextSiblingElement( const char* name = 0 ) {
return XMLHandle( _node ? _node->NextSiblingElement( name ) : 0 );
}
/// Safe cast to XMLNode. This can return null.
XMLNode* ToNode() {
return _node;
}
/// Safe cast to XMLElement. This can return null.
XMLElement* ToElement() {
return ( _node ? _node->ToElement() : 0 );
}
/// Safe cast to XMLText. This can return null.
XMLText* ToText() {
return ( _node ? _node->ToText() : 0 );
}
/// Safe cast to XMLUnknown. This can return null.
XMLUnknown* ToUnknown() {
return ( _node ? _node->ToUnknown() : 0 );
}
/// Safe cast to XMLDeclaration. This can return null.
XMLDeclaration* ToDeclaration() {
return ( _node ? _node->ToDeclaration() : 0 );
}
private: XMLNode* _node; };
/** A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the same in all regards, except for the 'const' qualifiers. See XMLHandle for API. / class TINYXML2_LIB XMLConstHandle { public: explicit XMLConstHandle( const XMLNode node ) : _node( node ) { } explicit XMLConstHandle( const XMLNode& node ) : _node( &node ) { } XMLConstHandle( const XMLConstHandle& ref ) : _node( ref._node ) { }
XMLConstHandle& operator=( const XMLConstHandle& ref ) {
_node = ref._node;
return *this;
}
const XMLConstHandle FirstChild() const {
return XMLConstHandle( _node ? _node->FirstChild() : 0 );
}
const XMLConstHandle FirstChildElement( const char* name = 0 ) const {
return XMLConstHandle( _node ? _node->FirstChildElement( name ) : 0 );
}
const XMLConstHandle LastChild() const {
return XMLConstHandle( _node ? _node->LastChild() : 0 );
}
const XMLConstHandle LastChildElement( const char* name = 0 ) const {
return XMLConstHandle( _node ? _node->LastChildElement( name ) : 0 );
}
const XMLConstHandle PreviousSibling() const {
return XMLConstHandle( _node ? _node->PreviousSibling() : 0 );
}
const XMLConstHandle PreviousSiblingElement( const char* name = 0 ) const {
return XMLConstHandle( _node ? _node->PreviousSiblingElement( name ) : 0 );
}
const XMLConstHandle NextSibling() const {
return XMLConstHandle( _node ? _node->NextSibling() : 0 );
}
const XMLConstHandle NextSiblingElement( const char* name = 0 ) const {
return XMLConstHandle( _node ? _node->NextSiblingElement( name ) : 0 );
}
const XMLNode* ToNode() const {
return _node;
}
const XMLElement* ToElement() const {
return ( _node ? _node->ToElement() : 0 );
}
const XMLText* ToText() const {
return ( _node ? _node->ToText() : 0 );
}
const XMLUnknown* ToUnknown() const {
return ( _node ? _node->ToUnknown() : 0 );
}
const XMLDeclaration* ToDeclaration() const {
return ( _node ? _node->ToDeclaration() : 0 );
}
private: const XMLNode* _node; };
/** Printing functionality. The XMLPrinter gives you more options than the XMLDocument::Print() method.
It can:
-# Print to memory.
-# Print to a file you provide.
-# Print XML without a XMLDocument.
Print to Memory
@verbatim
XMLPrinter printer;
doc.Print( &printer );
SomeFunction( printer.CStr() );
@endverbatim
Print to a File
You provide the file pointer.
@verbatim
XMLPrinter printer( fp );
doc.Print( &printer );
@endverbatim
Print without a XMLDocument
When loading, an XML parser is very useful. However, sometimes
when saving, it just gets in the way. The code is often set up
for streaming, and constructing the DOM is just overhead.
The Printer supports the streaming case. The following code
prints out a trivially simple XML file without ever creating
an XML document.
@verbatim
XMLPrinter printer( fp );
printer.OpenElement( "foo" );
printer.PushAttribute( "foo", "bar" );
printer.CloseElement();
@endverbatim
/ class TINYXML2_LIB XMLPrinter : public XMLVisitor { public: /* Construct the printer. If the FILE* is specified, this will print to the FILE. Else it will print to memory, and the result is available in CStr(). If 'compact' is set to true, then output is created with only required whitespace and newlines. / XMLPrinter( FILE file=0, bool compact = false, int depth = 0 ); virtual ~XMLPrinter() {}
/** If streaming, write the BOM and declaration. */
void PushHeader( bool writeBOM, bool writeDeclaration );
/** If streaming, start writing an element.
The element must be closed with CloseElement()
*/
void OpenElement( const char* name, bool compactMode=false );
/// If streaming, add an attribute to an open element.
void PushAttribute( const char* name, const char* value );
void PushAttribute( const char* name, int value );
void PushAttribute( const char* name, unsigned value );
void PushAttribute(const char* name, int64_t value);
void PushAttribute( const char* name, bool value );
void PushAttribute( const char* name, double value );
/// If streaming, close the Element.
virtual void CloseElement( bool compactMode=false );
/// Add a text node.
void PushText( const char* text, bool cdata=false );
/// Add a text node from an integer.
void PushText( int value );
/// Add a text node from an unsigned.
void PushText( unsigned value );
/// Add a text node from an unsigned.
void PushText(int64_t value);
/// Add a text node from a bool.
void PushText( bool value );
/// Add a text node from a float.
void PushText( float value );
/// Add a text node from a double.
void PushText( double value );
/// Add a comment
void PushComment( const char* comment );
void PushDeclaration( const char* value );
void PushUnknown( const char* value );
virtual bool VisitEnter( const XMLDocument& /*doc*/ );
virtual bool VisitExit( const XMLDocument& /*doc*/ ) {
return true;
}
virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute );
virtual bool VisitExit( const XMLElement& element );
virtual bool Visit( const XMLText& text );
virtual bool Visit( const XMLComment& comment );
virtual bool Visit( const XMLDeclaration& declaration );
virtual bool Visit( const XMLUnknown& unknown );
/**
If in print to memory mode, return a pointer to
the XML file in memory.
*/
const char* CStr() const {
return _buffer.Mem();
}
/**
If in print to memory mode, return the size
of the XML file in memory. (Note the size returned
includes the terminating null.)
*/
int CStrSize() const {
return _buffer.Size();
}
/**
If in print to memory mode, reset the buffer to the
beginning.
*/
void ClearBuffer() {
_buffer.Clear();
_buffer.Push(0);
_firstElement = true;
}
protected: virtual bool CompactMode( const XMLElement& ) { return _compactMode; }
/** Prints out the space before an element. You may override to change
the space and tabs used. A PrintSpace() override should call Print().
*/
virtual void PrintSpace( int depth );
void Print( const char* format, ... );
void Write( const char* data, size_t size );
inline void Write( const char* data ) { Write( data, strlen( data ) ); }
void Putc( char ch );
void SealElementIfJustOpened();
bool _elementJustOpened;
DynArray< const char*, 10 > _stack;
private: void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities.
bool _firstElement;
FILE* _fp;
int _depth;
int _textDepth;
bool _processEntities;
bool _compactMode;
enum {
ENTITY_RANGE = 64,
BUF_SIZE = 200
};
bool _entityFlag[ENTITY_RANGE];
bool _restrictedEntityFlag[ENTITY_RANGE];
DynArray< char, 20 > _buffer;
// Prohibit cloning, intentionally not implemented
XMLPrinter( const XMLPrinter& );
XMLPrinter& operator=( const XMLPrinter& );
};
} // tinyxml2
#if defined(_MSC_VER)
#endif
#endif // TINYXML2_INCLUDED
//Tnode.cpp======================================================================================================================
#include "common.h" #include "Tnode.h"
#ifdef TEST #include
const char* ftest = "test.txt"; void test(const char* name, uint32_t size, uint8_t* value) { fstream fp; fp.open(ftest, ios::app); if( name != nullptr ) fp << name; fp << "(" << size << "bytes): "; if( value != nullptr ) for( uint32_t i = 0; i < size; ++i ) fp << setfill('0')<< setw(2) << hex << (uint32_t)value[i] << ' '; fp << endl; } #endif
Tnode::Tnode() {}
Tnode::Tnode(char* n): name(n) {}
Tnode::Tnode(char* n, uint32_t s): name(n) { set(s); }
Tnode::Tnode(char* n, uint32_t s, uint32_t v) { set(s, v); }
Tnode::Tnode(char* n, uint32_t s, uint8_t* v): name(n) { set(s, v); }
Tnode::Tnode(char* n, FILE* fp): name(n) { set(fp); }
Tnode::Tnode(char* n, uint32_t s, FILE* fp): name(n) { set(s, fp); }
Tnode::~Tnode(void) { if( value ) delete[] value; if( cipher ) delete[] cipher; }
void Tnode::set(uint32_t s) { if( size != s ) { if( value != nullptr ) delete[] value; size = s; value = new uint8_tsize; } }
void Tnode::set(uint32_t s, uint32_t v) { set(s); memcpy(value, &v, size); }
void Tnode::set(uint32_t s, uint8_t* v) { set(s); memcpy(value, v, size); }
void Tnode::set(FILE* fp) { set(filelength(fileno(fp)) - ftell(fp)); if( size != 0 && fread(value, size, 1, fp) == 0 ) { if( name != nullptr ) cout << name << " "; cout << "read fail. " << endl; } }
void Tnode::set(uint32_t s, FILE* fp) { set(s); if( size != 0 && fread(value, size, 1, fp) == 0 ) { if( name != nullptr ) cout << name << " "; cout << "read fail. " << endl; } }
Tnode& Tnode::operator=(int v) { set(size, v); return *this; }
Tnode& Tnode::operator=(const char* v) { strcpy((char*)value, v); return *this; }
Tnode& Tnode::operator=(FILE* fp) { if(size == 0) size = filelength(fileno(fp)) - ftell(fp); set(size, fp); return *this; }
Tnode::operator uint32_t(void) { uint32_t v = 0; uint32_t s = size; if(size > 4) s = 4; memcpy(&v, value, s); return v; }
Tnode::operator uint8_t*(void) { return value; }
void Tnode::addChild(Tnode* child) { list<Tnode*>::iterator iter = children.end(); children.insert(iter, child); }
void Tnode::moveChild(Tnode& node) { for(Tnode* i: node.children) addChild(i); }
uint32_t Tnode::gsize(void) { uint32_t s = size; for( Tnode* i: children ) s += i->gsize(); return s; }
void Tnode::read(uint8_t* buf) { if( value == nullptr ) value = new uint8_tsize; memcpy(value, buf, size); uint32_t s = size; for( Tnode* i: children ) { i->read(buf + s); s += i->gsize(); } }
void Tnode::read(FILE* fp) { if( size != 0 && fread(value, size, 1, fp) == 0 ) { if( name != nullptr ) cout << name << " "; cout << "read fail. " << endl; } for( Tnode* i: children ) i->read(fp); }
void Tnode::write(uint8_t* buf) { memcpy(buf, value, size); uint32_t s = size; for( Tnode* i: children ) { i->write(buf + s); s += i->gsize(); } }
void Tnode::write(FILE* fp) { #ifdef TEST test(name, size, value); #endif if( cipher == nullptr ) { if( size != 0 && fwrite(value, size, 1, fp) == 0 ) { if( name != nullptr ) cout << name << " "; cout << "write fail. " << endl; } } else { if( size != 0 && fwrite(cipher, size, 1, fp) == 0 ) { if( name != nullptr ) cout << name << " "; cout << "write fail. " << endl; } #ifdef TEST test(name, size, cipher); #endif } for( Tnode* i: children ) i->write(fp); }
void Tnode::readcipher(uint8_t* buf) { uint32_t s = size; if(size > 0) { if( cipher == nullptr ) cipher = new uint8_tsize; memcpy(cipher, buf, size); } for( Tnode* i: children ) { i->readcipher(buf + s); s += i->gsize(); } }
void Tnode::readcipher(FILE* fp) { if(size > 0) { if( cipher == nullptr ) cipher = new uint8_tsize; if( size != 0 && fread(cipher, size, 1, fp) == 0 ) { if( name != nullptr ) cout << name << " "; cout << "read fail. " << endl; } } for( Tnode* i: children ) i->readcipher(fp); }
void Tnode::writeplain(FILE* fp) { if( size != 0 && fwrite(value, size, 1, fp) == 0 ) { if( name != nullptr ) cout << name << " "; cout << "write fail. " << endl; } for( Tnode* i: children ) i->writeplain(fp); }
void Tnode::writeplain(uint8_t* buf) { uint32_t s = size; if(size > 0) { memcpy(buf, value, size); } for( Tnode* i: children ) { i->writeplain(buf + s); s += i->gsize(); } }
void Tnode::writecipher(uint8_t* buf) { uint32_t s = size; if(size > 0) { memcpy(buf, cipher, size); } for( Tnode* i: children ) { i->writecipher(buf + s); s += i->gsize(); } }
void Tnode::clearcipher(void) { if(size > 0) { if( cipher != nullptr ) delete[] cipher; } for( Tnode* i: children ) i->clearcipher(); if( cipher != nullptr ) cipher = nullptr; }
Tnode* Tnode::find(const char* n) { Tnode* res; if( name != nullptr ) { if( strcmp(name, n) == 0 ) return this; } for( Tnode* i: children ) { if( i->name != nullptr ) { if( strcmp(i->name, n) == 0 ) return i; } } for( Tnode* i: children ) { res = i->find(n); if( res ) return res; } return nullptr; }
void Tnode::encrypt(const uint8_t* key, const uint8_t* iv, uint32_t ivlen) { uint32_t s = gsize(); if(s == 0) return; uint8_t *inbuf; uint8_t *outbuf; inbuf = new uint8_ts; outbuf = new uint8_ts; write(inbuf); AES_CTR(key, iv, ivlen, inbuf, outbuf, s); readcipher(outbuf); delete[] inbuf; delete[] outbuf; }
void Tnode::decrypt(const uint8_t* key, const uint8_t* iv, uint32_t ivlen) { uint32_t s = gsize(); if(s == 0) return; uint8_t *inbuf; uint8_t *outbuf; inbuf = new uint8_ts; outbuf = new uint8_ts; writecipher(inbuf); AES_CTR(key, iv, ivlen, inbuf, outbuf, s); read(outbuf); delete[] inbuf; delete[] outbuf; }
void Tnode::digest(Tnode& hash) { uint32_t s = gsize(); if(s == 0) return; uint8_t *inbuf; inbuf = new uint8_ts; write(inbuf); DigestArray(inbuf, s, hash.value); delete[] inbuf; }
bool Tnode::verifyDigest(Tnode& hash) { uint32_t s = gsize(); if(s == 0) return false; uint8_t *inbuf; uint8_t *outbuf; inbuf = new uint8_ts; outbuf = new uint8_tDigestLen; write(inbuf); DigestArray(inbuf, s, outbuf); delete[] inbuf; if( memcmp(outbuf, hash.value, DigestLen) == 0 ) { delete[] outbuf; return true; } delete[] outbuf; return false; }
bool Tnode::sign(Tnode& sig) { FILE* fp; const char* fdata = "temp.bin"; const char* fsig = "temp.sig";
fp = fopen(fdata, "wb");
write(fp);
fclose(fp);
bool res = signFile(fdata, SignToolPath, FixtureName, WorkerName, sig.value);
if( !res )
{
beforeExit();
throw;
}
remove(fdata);
remove(fsig);
return res;
}
bool Tnode::verify(Tnode& sig) { FILE* fp; const char* fdata = "temp.bin"; const char* fsig = "temp.sig";
fp = fopen(fdata, "wb");
writeplain(fp);
fclose(fp);
fp = fopen(fsig, "wb");
sig.writeplain(fp);
fclose(fp);
bool res = verifySignature(fdata, fsig, SignToolPath, "GWP_firmware.crt");
if( !res )
{
beforeExit();
throw;
}
remove(fdata);
remove(fsig);
return res;
}
//Tnode.h=====================================================================================================================================================
#ifndef _TNODE_H
#define _TNODE_H
#include
using namespace std;
class Tnode {
public:
const char* name = nullptr;
uint32_t size = 0;
uint8_t* value = nullptr;
uint8_t* cipher = nullptr;
list<Tnode*> children;
Tnode();
Tnode(char* n, uint32_t s);
Tnode(char* n);
Tnode(char* n, uint32_t s, uint32_t v);
Tnode(char* n, uint32_t s, uint8_t* v);
Tnode(char* n, FILE* fp);
Tnode(char* n, uint32_t s, FILE* fp);
~Tnode(void);
void set(uint32_t s);
void set(uint8_t* buf);
void set(uint32_t s, uint32_t v);
void set(uint32_t s, uint8_t* v);
void set(FILE* fp);
void set(uint32_t s, FILE* fp);
Tnode& operator=(int v);
Tnode& operator=(const char* v);
Tnode& operator=(FILE* fp);
operator uint8_t*(void);
operator uint32_t(void);
void addChild(Tnode* child);
void moveChild(Tnode& node);
uint32_t gsize(void);
void read(uint8_t* buf);
void read(FILE* fp);
void write(uint8_t* buf);
void write(FILE* fp);
void readcipher(uint8_t* buf);
void readcipher(FILE* fp);
void writeplain(FILE* fp);
void writeplain(uint8_t* buf);
void writecipher(uint8_t* buf);
void clearcipher(void);
Tnode* find(const char* n);
void encrypt(const uint8_t* key, const uint8_t* iv, uint32_t ivlen);
void decrypt(const uint8_t* key, const uint8_t* iv, uint32_t ivlen);
void digest(Tnode& hash);
bool verifyDigest(Tnode& hash);
bool sign(Tnode& sig);
bool verify(Tnode& sig);
};
#endif // _TNODE_H
//version.h============================================================================================================================================================
#define OPGT_VERSION 0x01000001
//aes.h========================================================================================= // aes.h - originally written and placed in the public domain by Wei Dai
/// \file /// \brief Class file for the AES cipher (Rijndael) /// \details AES is a typdef for Rijndael classes. All key sizes are supported. /// The library only provides Rijndael with 128-bit blocks, and not 192-bit or 256-bit blocks /// \since Rijndael since Crypto++ 3.1, Intel AES-NI since Crypto++ 5.6.1, ARMv8 AES since Crypto++ 6.0, /// Power8 AES since Crypto++ 6.0
#ifndef CRYPTOPP_AES_H #define CRYPTOPP_AES_H
#include "rijndael.h"
NAMESPACE_BEGIN(CryptoPP)
/// \brief AES block cipher (Rijndael) /// \details AES is a typdef for Rijndael classes. All key sizes are supported. /// The library only provides Rijndael with 128-bit blocks, and not 192-bit or 256-bit blocks /// \sa AES winner, announced on 10/2/2000 /// \since Rijndael since Crypto++ 3.1, Intel AES-NI since Crypto++ 5.6.1, ARMv8 AES since Crypto++ 6.0, /// Power8 AES since Crypto++ 6.0 DOCUMENTED_TYPEDEF(Rijndael, AES)
typedef RijndaelEncryption AESEncryption; typedef RijndaelDecryption AESDecryption;
NAMESPACE_END
#endif
//algparam.h========================================================================================
// algparam.h - originally written and placed in the public domain by Wei Dai
/// \file algparam.h /// \brief Classes for working with NameValuePairs
#ifndef CRYPTOPP_ALGPARAM_H #define CRYPTOPP_ALGPARAM_H
#include "config.h" #include "cryptlib.h"
#include "smartptr.h" #include "secblock.h" #include "integer.h" #include "misc.h"
NAMESPACE_BEGIN(CryptoPP)
/// \brief Used to pass byte array input as part of a NameValuePairs object class ConstByteArrayParameter { public: /// \brief Construct a ConstByteArrayParameter /// \param data a C-String /// \param deepCopy flag indicating whether the data should be copied /// \details The deepCopy option is used when the NameValuePairs object can't /// keep a copy of the data available ConstByteArrayParameter(const char *data = NULLPTR, bool deepCopy = false) : m_deepCopy(false), m_data(NULLPTR), m_size(0) { Assign(reinterpret_cast<const byte *>(data), data ? strlen(data) : 0, deepCopy); }
/// \brief Construct a ConstByteArrayParameter
/// \param data a memory buffer
/// \param size the length of the memory buffer
/// \param deepCopy flag indicating whether the data should be copied
/// \details The deepCopy option is used when the NameValuePairs object can't
/// keep a copy of the data available
ConstByteArrayParameter(const byte *data, size_t size, bool deepCopy = false)
: m_deepCopy(false), m_data(NULLPTR), m_size(0)
{
Assign(data, size, deepCopy);
}
/// \brief Construct a ConstByteArrayParameter
/// \tparam T a std::basic_string<char> or std::vector<byte> class
/// \param string a std::basic_string<char> or std::vector<byte> object
/// \param deepCopy flag indicating whether the data should be copied
/// \details The deepCopy option is used when the NameValuePairs object can't
/// keep a copy of the data available
template <class T> ConstByteArrayParameter(const T &string, bool deepCopy = false)
: m_deepCopy(false), m_data(NULLPTR), m_size(0)
{
CRYPTOPP_COMPILE_ASSERT(sizeof(typename T::value_type) == 1);
Assign(reinterpret_cast<const byte *>(&string[0]), string.size(), deepCopy);
}
/// \brief Assign contents from a memory buffer
/// \param data a memory buffer
/// \param size the length of the memory buffer
/// \param deepCopy flag indicating whether the data should be copied
/// \details The deepCopy option is used when the NameValuePairs object can't
/// keep a copy of the data available
void Assign(const byte *data, size_t size, bool deepCopy)
{
// This fires, which means: no data with a size, or data with no size.
// CRYPTOPP_ASSERT((data && size) || !(data || size));
if (deepCopy)
m_block.Assign(data, size);
else
{
m_data = data;
m_size = size;
}
m_deepCopy = deepCopy;
}
/// \brief Pointer to the first byte in the memory block
const byte *begin() const {return m_deepCopy ? m_block.begin() : m_data;}
/// \brief Pointer beyond the last byte in the memory block
const byte *end() const {return m_deepCopy ? m_block.end() : m_data + m_size;}
/// \brief Length of the memory block
size_t size() const {return m_deepCopy ? m_block.size() : m_size;}
private: bool m_deepCopy; const byte *m_data; size_t m_size; SecByteBlock m_block; };
/// \brief Used to pass byte array input as part of a NameValuePairs object class ByteArrayParameter { public: /// \brief Construct a ByteArrayParameter /// \param data a memory buffer /// \param size the length of the memory buffer ByteArrayParameter(byte *data = NULLPTR, unsigned int size = 0) : m_data(data), m_size(size) {}
/// \brief Construct a ByteArrayParameter
/// \param block a SecByteBlock
ByteArrayParameter(SecByteBlock &block)
: m_data(block.begin()), m_size(block.size()) {}
/// \brief Pointer to the first byte in the memory block
byte *begin() const {return m_data;}
/// \brief Pointer beyond the last byte in the memory block
byte *end() const {return m_data + m_size;}
/// \brief Length of the memory block
size_t size() const {return m_size;}
private: byte *m_data; size_t m_size; };
/// \brief Combines two sets of NameValuePairs /// \details CombinedNameValuePairs allows you to provide two sets of of NameValuePairs. /// If a name is not found in the first set, then the second set is searched for the /// name and value pair. The second set of NameValuePairs often provides default values. class CRYPTOPP_DLL CombinedNameValuePairs : public NameValuePairs { public: /// \brief Construct a CombinedNameValuePairs /// \param pairs1 reference to the first set of NameValuePairs /// \param pairs2 reference to the second set of NameValuePairs CombinedNameValuePairs(const NameValuePairs &pairs1, const NameValuePairs &pairs2) : m_pairs1(pairs1), m_pairs2(pairs2) {}
bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const;
private: const NameValuePairs &m_pairs1, &m_pairs2; };
#ifndef CRYPTOPP_DOXYGEN_PROCESSING template <class T, class BASE> class GetValueHelperClass { public: GetValueHelperClass(const T *pObject, const char *name, const std::type_info &valueType, void *pValue, const NameValuePairs *searchFirst) : m_pObject(pObject), m_name(name), m_valueType(&valueType), m_pValue(pValue), m_found(false), m_getValueNames(false) { if (strcmp(m_name, "ValueNames") == 0) { m_found = m_getValueNames = true; NameValuePairs::ThrowIfTypeMismatch(m_name, typeid(std::string), *m_valueType); if (searchFirst) searchFirst->GetVoidValue(m_name, valueType, pValue); if (typeid(T) != typeid(BASE)) pObject->BASE::GetVoidValue(m_name, valueType, pValue); ((*reinterpret_cast<std::string *>(m_pValue) += "ThisPointer:") += typeid(T).name()) += ';'; }
if (!m_found && strncmp(m_name, "ThisPointer:", 12) == 0 && strcmp(m_name+12, typeid(T).name()) == 0)
{
NameValuePairs::ThrowIfTypeMismatch(m_name, typeid(T *), *m_valueType);
*reinterpret_cast<const T **>(pValue) = pObject;
m_found = true;
return;
}
if (!m_found && searchFirst)
m_found = searchFirst->GetVoidValue(m_name, valueType, pValue);
if (!m_found && typeid(T) != typeid(BASE))
m_found = pObject->BASE::GetVoidValue(m_name, valueType, pValue);
}
operator bool() const {return m_found;}
template <class R>
GetValueHelperClass<T,BASE> & operator()(const char *name, const R & (T::*pm)() const)
{
if (m_getValueNames)
(*reinterpret_cast<std::string *>(m_pValue) += name) += ";";
if (!m_found && strcmp(name, m_name) == 0)
{
NameValuePairs::ThrowIfTypeMismatch(name, typeid(R), *m_valueType);
*reinterpret_cast<R *>(m_pValue) = (m_pObject->*pm)();
m_found = true;
}
return *this;
}
GetValueHelperClass<T,BASE> &Assignable()
{
#ifndef __INTEL_COMPILER // ICL 9.1 workaround: Intel compiler copies the vTable pointer for some reason if (m_getValueNames) ((*reinterpret_cast<std::string *>(m_pValue) += "ThisObject:") += typeid(T).name()) += ';'; if (!m_found && strncmp(m_name, "ThisObject:", 11) == 0 && strcmp(m_name+11, typeid(T).name()) == 0) { NameValuePairs::ThrowIfTypeMismatch(m_name, typeid(T), *m_valueType); *reinterpret_cast<T *>(m_pValue) = *m_pObject; m_found = true; } #endif return *this; }
private: const T *m_pObject; const char *m_name; const std::type_info *m_valueType; void *m_pValue; bool m_found, m_getValueNames; };
template <class BASE, class T> GetValueHelperClass<T, BASE> GetValueHelper(const T *pObject, const char *name, const std::type_info &valueType, void *pValue, const NameValuePairs *searchFirst=NULLPTR) { return GetValueHelperClass<T, BASE>(pObject, name, valueType, pValue, searchFirst); }
template GetValueHelperClass<T, T> GetValueHelper(const T *pObject, const char *name, const std::type_info &valueType, void *pValue, const NameValuePairs *searchFirst=NULLPTR) { return GetValueHelperClass<T, T>(pObject, name, valueType, pValue, searchFirst); }
// ********************************************************
template <class T, class BASE> class AssignFromHelperClass { public: AssignFromHelperClass(T *pObject, const NameValuePairs &source) : m_pObject(pObject), m_source(source), m_done(false) { if (source.GetThisObject(*pObject)) m_done = true; else if (typeid(BASE) != typeid(T)) pObject->BASE::AssignFrom(source); }
template <class R>
AssignFromHelperClass & operator()(const char *name, void (T::*pm)(const R&))
{
if (!m_done)
{
R value;
if (!m_source.GetValue(name, value))
throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name + "'");
(m_pObject->*pm)(value);
}
return *this;
}
template <class R, class S>
AssignFromHelperClass & operator()(const char *name1, const char *name2, void (T::*pm)(const R&, const S&))
{
if (!m_done)
{
R value1;
if (!m_source.GetValue(name1, value1))
throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name1 + "'");
S value2;
if (!m_source.GetValue(name2, value2))
throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name2 + "'");
(m_pObject->*pm)(value1, value2);
}
return *this;
}
private: T *m_pObject; const NameValuePairs &m_source; bool m_done; };
template <class BASE, class T> AssignFromHelperClass<T, BASE> AssignFromHelper(T *pObject, const NameValuePairs &source) { return AssignFromHelperClass<T, BASE>(pObject, source); }
template AssignFromHelperClass<T, T> AssignFromHelper(T *pObject, const NameValuePairs &source) { return AssignFromHelperClass<T, T>(pObject, source); }
#endif // CRYPTOPP_DOXYGEN_PROCESSING
// ********************************************************
#ifndef CRYPTOPP_NO_ASSIGN_TO_INTEGER // Allow the linker to discard Integer code if not needed. // Also see http://github.com/weidai11/cryptopp/issues/389. CRYPTOPP_DLL bool AssignIntToInteger(const std::type_info &valueType, void *pInteger, const void *pInt); #endif
CRYPTOPP_DLL const std::type_info & CRYPTOPP_API IntegerTypeId();
/// \brief Base class for AlgorithmParameters class CRYPTOPP_DLL AlgorithmParametersBase { public: /// \brief Exception thrown when an AlgorithmParameter is unused class ParameterNotUsed : public Exception { public: ParameterNotUsed(const char *name) : Exception(OTHER_ERROR, std::string("AlgorithmParametersBase: parameter "") + name + "" not used") {} };
virtual ~AlgorithmParametersBase() CRYPTOPP_THROW
{
#if defined(CRYPTOPP_CXX17_EXCEPTIONS) if (std::uncaught_exceptions() == 0) #elif defined(CRYPTOPP_UNCAUGHT_EXCEPTION_AVAILABLE) if (std::uncaught_exception() == false) #else try #endif { if (m_throwIfNotUsed && !m_used) throw ParameterNotUsed(m_name); } #if !defined(CRYPTOPP_CXX17_EXCEPTIONS) && !defined(CRYPTOPP_UNCAUGHT_EXCEPTION_AVAILABLE) catch(const Exception&) { } #endif }
// this is actually a move, not a copy
AlgorithmParametersBase(const AlgorithmParametersBase &x)
: m_name(x.m_name), m_throwIfNotUsed(x.m_throwIfNotUsed), m_used(x.m_used)
{
m_next.reset(const_cast<AlgorithmParametersBase &>(x).m_next.release());
x.m_used = true;
}
/// \brief Construct a AlgorithmParametersBase
/// \param name the parameter name
/// \param throwIfNotUsed flags indicating whether an exception should be thrown
/// \details If throwIfNotUsed is true, then a ParameterNotUsed exception
/// will be thrown in the destructor if the parameter is not not retrieved.
AlgorithmParametersBase(const char *name, bool throwIfNotUsed)
: m_name(name), m_throwIfNotUsed(throwIfNotUsed), m_used(false) {}
bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const;
protected: friend class AlgorithmParameters; void operator=(const AlgorithmParametersBase& rhs); // assignment not allowed, declare this for VC60
virtual void AssignValue(const char *name, const std::type_info &valueType, void *pValue) const =0;
virtual void MoveInto(void *p) const =0; // not really const
const char *m_name;
bool m_throwIfNotUsed;
mutable bool m_used;
member_ptr<AlgorithmParametersBase> m_next;
};
/// \brief Template base class for AlgorithmParameters /// \tparam T the class or type template class AlgorithmParametersTemplate : public AlgorithmParametersBase { public: /// \brief Construct an AlgorithmParametersTemplate /// \param name the name of the value /// \param value a reference to the value /// \param throwIfNotUsed flags indicating whether an exception should be thrown /// \details If throwIfNotUsed is true, then a ParameterNotUsed exception /// will be thrown in the destructor if the parameter is not not retrieved. AlgorithmParametersTemplate(const char *name, const T &value, bool throwIfNotUsed) : AlgorithmParametersBase(name, throwIfNotUsed), m_value(value) { }
void AssignValue(const char *name, const std::type_info &valueType, void *pValue) const
{
#ifndef CRYPTOPP_NO_ASSIGN_TO_INTEGER // Special case for retrieving an Integer parameter when an int was passed in if (!(typeid(T) == typeid(int) && AssignIntToInteger(valueType, pValue, &m_value))) #endif { NameValuePairs::ThrowIfTypeMismatch(name, typeid(T), valueType); *reinterpret_cast<T *>(pValue) = m_value; } }
#if defined(DEBUG_NEW) && (_MSC_VER >= 1300)
#endif
void MoveInto(void *buffer) const
{
AlgorithmParametersTemplate<T>* p = new(buffer) AlgorithmParametersTemplate<T>(*this);
CRYPTOPP_UNUSED(p); // silence warning
}
#if defined(DEBUG_NEW) && (_MSC_VER >= 1300)
#endif
protected: T m_value; };
CRYPTOPP_DLL_TEMPLATE_CLASS AlgorithmParametersTemplate; CRYPTOPP_DLL_TEMPLATE_CLASS AlgorithmParametersTemplate; CRYPTOPP_DLL_TEMPLATE_CLASS AlgorithmParametersTemplate;
/// \brief An object that implements NameValuePairs /// \note A NameValuePairs object containing an arbitrary number of name value pairs may be constructed by /// repeatedly using operator() on the object returned by MakeParameters, for example: ///
/// AlgorithmParameters parameters = MakeParameters(name1, value1)(name2, value2)(name3, value3); ///class CRYPTOPP_DLL AlgorithmParameters : public NameValuePairs { public: /// \brief Construct a AlgorithmParameters /// \note A NameValuePairs object containing an arbitrary number of name value pairs may be constructed by /// repeatedly using operator() on the object returned by MakeParameters, for example: ///
/// AlgorithmParameters parameters = MakeParameters(name1, value1)(name2, value2)(name3, value3); ///AlgorithmParameters();
#ifdef BORLANDC /// \brief Construct a AlgorithmParameters /// \tparam T the class or type /// \param name the name of the object or value to retrieve /// \param value reference to a variable that receives the value /// \param throwIfNotUsed if true, the object will throw an exception if the value is not accessed /// \note throwIfNotUsed is ignored if using a compiler that does not support std::uncaught_exception(), /// such as MSVC 7.0 and earlier. /// \note A NameValuePairs object containing an arbitrary number of name value pairs may be constructed by /// repeatedly using operator() on the object returned by MakeParameters, for example: ///
/// AlgorithmParameters parameters = MakeParameters(name1, value1)(name2, value2)(name3, value3); ///template AlgorithmParameters(const char *name, const T &value, bool throwIfNotUsed=true) : m_next(new AlgorithmParametersTemplate(name, value, throwIfNotUsed)) , m_defaultThrowIfNotUsed(throwIfNotUsed) { } #endif
AlgorithmParameters(const AlgorithmParameters &x);
AlgorithmParameters & operator=(const AlgorithmParameters &x);
/// \tparam T the class or type
/// \param name the name of the object or value to retrieve
/// \param value reference to a variable that receives the value
/// \param throwIfNotUsed if true, the object will throw an exception if the value is not accessed
template <class T>
AlgorithmParameters & operator()(const char *name, const T &value, bool throwIfNotUsed)
{
member_ptr<AlgorithmParametersBase> p(new AlgorithmParametersTemplate<T>(name, value, throwIfNotUsed));
p->m_next.reset(m_next.release());
m_next.reset(p.release());
m_defaultThrowIfNotUsed = throwIfNotUsed;
return *this;
}
/// \brief Appends a NameValuePair to a collection of NameValuePairs
/// \tparam T the class or type
/// \param name the name of the object or value to retrieve
/// \param value reference to a variable that receives the value
template <class T>
AlgorithmParameters & operator()(const char *name, const T &value)
{
return operator()(name, value, m_defaultThrowIfNotUsed);
}
bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const;
protected: member_ptr m_next; bool m_defaultThrowIfNotUsed; };
/// \brief Create an object that implements NameValuePairs /// \tparam T the class or type /// \param name the name of the object or value to retrieve /// \param value reference to a variable that receives the value /// \param throwIfNotUsed if true, the object will throw an exception if the value is not accessed /// \note throwIfNotUsed is ignored if using a compiler that does not support std::uncaught_exception(), /// such as MSVC 7.0 and earlier. /// \note A NameValuePairs object containing an arbitrary number of name value pairs may be constructed by /// repeatedly using \p operator() on the object returned by \p MakeParameters, for example: ///
/// AlgorithmParameters parameters = MakeParameters(name1, value1)(name2, value2)(name3, value3); ///#ifdef BORLANDC typedef AlgorithmParameters MakeParameters; #else template AlgorithmParameters MakeParameters(const char *name, const T &value, bool throwIfNotUsed = true) { return AlgorithmParameters()(name, value, throwIfNotUsed); } #endif
#define CRYPTOPP_GET_FUNCTION_ENTRY(name) (Name::name(), &ThisClass::Get##name) #define CRYPTOPP_SET_FUNCTION_ENTRY(name) (Name::name(), &ThisClass::Set##name) #define CRYPTOPP_SET_FUNCTION_ENTRY2(name1, name2) (Name::name1(), Name::name2(), &ThisClass::Set##name1##And##name2)
NAMESPACE_END
#endif
//argnames.h==============================================================================
// argnames.h - originally written and placed in the public domain by Wei Dai
/// \file argnames.h /// \brief Standard names for retrieving values by name when working with \p NameValuePairs
#ifndef CRYPTOPP_ARGNAMES_H #define CRYPTOPP_ARGNAMES_H
#include "cryptlib.h"
NAMESPACE_BEGIN(CryptoPP)
DOCUMENTED_NAMESPACE_BEGIN(Name)
#define CRYPTOPP_DEFINE_NAME_STRING(name) inline const char *name() {return #name;}
CRYPTOPP_DEFINE_NAME_STRING(ValueNames) ///< string, a list of value names with a semicolon (';') after each name CRYPTOPP_DEFINE_NAME_STRING(Version) ///< int CRYPTOPP_DEFINE_NAME_STRING(Seed) ///< ConstByteArrayParameter CRYPTOPP_DEFINE_NAME_STRING(Key) ///< ConstByteArrayParameter CRYPTOPP_DEFINE_NAME_STRING(IV) ///< ConstByteArrayParameter, also accepts const byte * for backwards compatibility CRYPTOPP_DEFINE_NAME_STRING(StolenIV) ///< byte * CRYPTOPP_DEFINE_NAME_STRING(Nonce) ///< ConstByteArrayParameter CRYPTOPP_DEFINE_NAME_STRING(Rounds) ///< int CRYPTOPP_DEFINE_NAME_STRING(FeedbackSize) ///< int CRYPTOPP_DEFINE_NAME_STRING(WordSize) ///< int, in bytes CRYPTOPP_DEFINE_NAME_STRING(BlockSize) ///< int, in bytes CRYPTOPP_DEFINE_NAME_STRING(EffectiveKeyLength) ///< int, in bits CRYPTOPP_DEFINE_NAME_STRING(KeySize) ///< int, in bits CRYPTOPP_DEFINE_NAME_STRING(ModulusSize) ///< int, in bits CRYPTOPP_DEFINE_NAME_STRING(SubgroupOrderSize) ///< int, in bits CRYPTOPP_DEFINE_NAME_STRING(PrivateExponentSize)///< int, in bits CRYPTOPP_DEFINE_NAME_STRING(Modulus) ///< Integer CRYPTOPP_DEFINE_NAME_STRING(PublicExponent) ///< Integer CRYPTOPP_DEFINE_NAME_STRING(PrivateExponent) ///< Integer CRYPTOPP_DEFINE_NAME_STRING(PublicElement) ///< Integer CRYPTOPP_DEFINE_NAME_STRING(SubgroupOrder) ///< Integer CRYPTOPP_DEFINE_NAME_STRING(Cofactor) ///< Integer CRYPTOPP_DEFINE_NAME_STRING(SubgroupGenerator) ///< Integer, ECP::Point, or EC2N::Point CRYPTOPP_DEFINE_NAME_STRING(Curve) ///< ECP or EC2N CRYPTOPP_DEFINE_NAME_STRING(GroupOID) ///< OID CRYPTOPP_DEFINE_NAME_STRING(PointerToPrimeSelector) ///< const PrimeSelector * CRYPTOPP_DEFINE_NAME_STRING(Prime1) ///< Integer CRYPTOPP_DEFINE_NAME_STRING(Prime2) ///< Integer CRYPTOPP_DEFINE_NAME_STRING(ModPrime1PrivateExponent) ///< Integer CRYPTOPP_DEFINE_NAME_STRING(ModPrime2PrivateExponent) ///< Integer CRYPTOPP_DEFINE_NAME_STRING(MultiplicativeInverseOfPrime2ModPrime1) ///< Integer CRYPTOPP_DEFINE_NAME_STRING(QuadraticResidueModPrime1) ///< Integer CRYPTOPP_DEFINE_NAME_STRING(QuadraticResidueModPrime2) ///< Integer CRYPTOPP_DEFINE_NAME_STRING(PutMessage) ///< bool CRYPTOPP_DEFINE_NAME_STRING(TruncatedDigestSize) ///< int CRYPTOPP_DEFINE_NAME_STRING(BlockPaddingScheme) ///< StreamTransformationFilter::BlockPaddingScheme CRYPTOPP_DEFINE_NAME_STRING(HashVerificationFilterFlags) ///< word32 CRYPTOPP_DEFINE_NAME_STRING(AuthenticatedDecryptionFilterFlags) ///< word32 CRYPTOPP_DEFINE_NAME_STRING(SignatureVerificationFilterFlags) ///< word32 CRYPTOPP_DEFINE_NAME_STRING(InputBuffer) ///< ConstByteArrayParameter CRYPTOPP_DEFINE_NAME_STRING(OutputBuffer) ///< ByteArrayParameter CRYPTOPP_DEFINE_NAME_STRING(InputFileName) ///< const char * CRYPTOPP_DEFINE_NAME_STRING(InputFileNameWide) ///< const wchar_t * CRYPTOPP_DEFINE_NAME_STRING(InputStreamPointer) ///< std::istream * CRYPTOPP_DEFINE_NAME_STRING(InputBinaryMode) ///< bool CRYPTOPP_DEFINE_NAME_STRING(OutputFileName) ///< const char * CRYPTOPP_DEFINE_NAME_STRING(OutputFileNameWide) ///< const wchar_t * CRYPTOPP_DEFINE_NAME_STRING(OutputStreamPointer) ///< std::ostream * CRYPTOPP_DEFINE_NAME_STRING(OutputBinaryMode) ///< bool CRYPTOPP_DEFINE_NAME_STRING(EncodingParameters) ///< ConstByteArrayParameter CRYPTOPP_DEFINE_NAME_STRING(KeyDerivationParameters) ///< ConstByteArrayParameter CRYPTOPP_DEFINE_NAME_STRING(Separator) ///< ConstByteArrayParameter CRYPTOPP_DEFINE_NAME_STRING(Terminator) ///< ConstByteArrayParameter CRYPTOPP_DEFINE_NAME_STRING(Uppercase) ///< bool CRYPTOPP_DEFINE_NAME_STRING(GroupSize) ///< int CRYPTOPP_DEFINE_NAME_STRING(Pad) ///< bool CRYPTOPP_DEFINE_NAME_STRING(PaddingByte) ///< byte CRYPTOPP_DEFINE_NAME_STRING(Log2Base) ///< int CRYPTOPP_DEFINE_NAME_STRING(EncodingLookupArray) ///< const byte * CRYPTOPP_DEFINE_NAME_STRING(DecodingLookupArray) ///< const byte * CRYPTOPP_DEFINE_NAME_STRING(InsertLineBreaks) ///< bool CRYPTOPP_DEFINE_NAME_STRING(MaxLineLength) ///< int CRYPTOPP_DEFINE_NAME_STRING(DigestSize) ///< int, in bytes CRYPTOPP_DEFINE_NAME_STRING(L1KeyLength) ///< int, in bytes CRYPTOPP_DEFINE_NAME_STRING(TableSize) ///< int, in bytes CRYPTOPP_DEFINE_NAME_STRING(Blinding) ///< bool, timing attack mitigations, ON by default CRYPTOPP_DEFINE_NAME_STRING(DerivedKey) ///< ByteArrayParameter, key derivation, derived key CRYPTOPP_DEFINE_NAME_STRING(DerivedKeyLength) ///< int, key derivation, derived key length in bytes CRYPTOPP_DEFINE_NAME_STRING(Personalization) ///< ConstByteArrayParameter CRYPTOPP_DEFINE_NAME_STRING(PersonalizationSize) ///< int, in bytes CRYPTOPP_DEFINE_NAME_STRING(Salt) ///< ConstByteArrayParameter CRYPTOPP_DEFINE_NAME_STRING(Tweak) ///< ConstByteArrayParameter CRYPTOPP_DEFINE_NAME_STRING(SaltSize) ///< int, in bytes CRYPTOPP_DEFINE_NAME_STRING(TreeMode) ///< byte CRYPTOPP_DEFINE_NAME_STRING(FileName) ///< const char * CRYPTOPP_DEFINE_NAME_STRING(FileTime) ///< int CRYPTOPP_DEFINE_NAME_STRING(Comment) ///< const char * CRYPTOPP_DEFINE_NAME_STRING(Identity) ///< ConstByteArrayParameter DOCUMENTED_NAMESPACE_END
NAMESPACE_END
#endif
//asn.h================================================================================
// asn.h - originally written and placed in the public domain by Wei Dai
/// \file asn.h /// \brief Classes and functions for working with ANS.1 objects
#ifndef CRYPTOPP_ASN_H #define CRYPTOPP_ASN_H
#include "cryptlib.h" #include "filters.h" #include "smartptr.h" #include "stdcpp.h" #include "queue.h" #include "misc.h"
// Issue 340 #if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE
#endif
NAMESPACE_BEGIN(CryptoPP)
/// \brief ASN.1 types /// \note These tags and flags are not complete enum ASNTag { BOOLEAN = 0x01, INTEGER = 0x02, BIT_STRING = 0x03, OCTET_STRING = 0x04, TAG_NULL = 0x05, OBJECT_IDENTIFIER = 0x06, OBJECT_DESCRIPTOR = 0x07, EXTERNAL = 0x08, REAL = 0x09, ENUMERATED = 0x0a, UTF8_STRING = 0x0c, SEQUENCE = 0x10, SET = 0x11, NUMERIC_STRING = 0x12, PRINTABLE_STRING = 0x13, T61_STRING = 0x14, VIDEOTEXT_STRING = 0x15, IA5_STRING = 0x16, UTC_TIME = 0x17, GENERALIZED_TIME = 0x18, GRAPHIC_STRING = 0x19, VISIBLE_STRING = 0x1a, GENERAL_STRING = 0x1b };
/// \brief ASN.1 flags /// \note These tags and flags are not complete enum ASNIdFlag { UNIVERSAL = 0x00, // DATA = 0x01, // HEADER = 0x02, PRIMITIVE = 0x00, CONSTRUCTED = 0x20, APPLICATION = 0x40, CONTEXT_SPECIFIC = 0x80, PRIVATE = 0xc0 };
/// \brief Raises a BERDecodeErr inline void BERDecodeError() {throw BERDecodeErr();}
/// \brief Exception thrown when an unknown object identifier is encountered class CRYPTOPP_DLL UnknownOID : public BERDecodeErr { public: /// \brief Construct an UnknownOID UnknownOID() : BERDecodeErr("BER decode error: unknown object identifier") {} /// \brief Construct an UnknownOID /// \param err error message to use for the execption UnknownOID(const char *err) : BERDecodeErr(err) {} };
// unsigned int DERLengthEncode(unsigned int length, byte *output=0);
/// \brief DER encode a length /// \param bt BufferedTransformation object for writing /// \param length the size to encode /// \returns the number of octets used for the encoding CRYPTOPP_DLL size_t CRYPTOPP_API DERLengthEncode(BufferedTransformation &bt, lword length);
/// \brief BER decode a length /// \param bt BufferedTransformation object for reading /// \param length the decoded size /// \returns true if the value was decoded /// \throws BERDecodeError if the value fails to decode or is too large for size_t /// \details BERLengthDecode() returns false if the encoding is indefinite length. CRYPTOPP_DLL bool CRYPTOPP_API BERLengthDecode(BufferedTransformation &bt, size_t &length);
/// \brief DER encode NULL /// \param bt BufferedTransformation object for writing CRYPTOPP_DLL void CRYPTOPP_API DEREncodeNull(BufferedTransformation &bt);
/// \brief BER decode NULL /// \param bt BufferedTransformation object for reading CRYPTOPP_DLL void CRYPTOPP_API BERDecodeNull(BufferedTransformation &bt);
/// \brief DER encode octet string /// \param bt BufferedTransformation object for writing /// \param str the string to encode /// \param strLen the length of the string /// \returns the number of octets used for the encoding CRYPTOPP_DLL size_t CRYPTOPP_API DEREncodeOctetString(BufferedTransformation &bt, const byte *str, size_t strLen);
/// \brief DER encode octet string /// \param bt BufferedTransformation object for reading /// \param str the string to encode /// \returns the number of octets used for the encoding CRYPTOPP_DLL size_t CRYPTOPP_API DEREncodeOctetString(BufferedTransformation &bt, const SecByteBlock &str);
/// \brief BER decode octet string /// \param bt BufferedTransformation object for reading /// \param str the decoded string /// \returns the number of octets used for the encoding CRYPTOPP_DLL size_t CRYPTOPP_API BERDecodeOctetString(BufferedTransformation &bt, SecByteBlock &str);
/// \brief BER decode octet string /// \param bt BufferedTransformation object for reading /// \param str the decoded string /// \returns the number of octets used for the encoding CRYPTOPP_DLL size_t CRYPTOPP_API BERDecodeOctetString(BufferedTransformation &bt, BufferedTransformation &str);
/// \brief DER encode text string /// \param bt BufferedTransformation object for writing /// \param str the string to encode /// \param asnTag the ASN.1 type /// \returns the number of octets used for the encoding /// \details DEREncodeTextString() can be used for UTF8_STRING, PRINTABLE_STRING, and IA5_STRING CRYPTOPP_DLL size_t CRYPTOPP_API DEREncodeTextString(BufferedTransformation &bt, const std::string &str, byte asnTag);
/// \brief BER decode text string /// \param bt BufferedTransformation object for reading /// \param str the string to encode /// \param asnTag the ASN.1 type /// \details DEREncodeTextString() can be used for UTF8_STRING, PRINTABLE_STRING, and IA5_STRING CRYPTOPP_DLL size_t CRYPTOPP_API BERDecodeTextString(BufferedTransformation &bt, std::string &str, byte asnTag);
/// \brief DER encode bit string /// \param bt BufferedTransformation object for writing /// \param str the string to encode /// \param strLen the length of the string /// \param unusedBits the number of unused bits /// \returns the number of octets used for the encoding CRYPTOPP_DLL size_t CRYPTOPP_API DEREncodeBitString(BufferedTransformation &bt, const byte *str, size_t strLen, unsigned int unusedBits=0);
/// \brief DER decode bit string /// \param bt BufferedTransformation object for reading /// \param str the decoded string /// \param unusedBits the number of unused bits CRYPTOPP_DLL size_t CRYPTOPP_API BERDecodeBitString(BufferedTransformation &bt, SecByteBlock &str, unsigned int &unusedBits);
/// \brief BER decode and DER re-encode /// \param bt BufferedTransformation object for writing /// \param dest BufferedTransformation object CRYPTOPP_DLL void CRYPTOPP_API DERReencode(BufferedTransformation &bt, BufferedTransformation &dest);
/// \brief Object Identifier class CRYPTOPP_DLL OID { public: virtual ~OID() {}
/// \brief Construct an OID
OID() {}
/// \brief Construct an OID
/// \param v value to initialize the OID
OID(word32 v) : m_values(1, v) {}
/// \brief Construct an OID
/// \param bt BufferedTransformation object
OID(BufferedTransformation &bt) {BERDecode(bt);}
/// \brief Append a value to an OID
/// \param rhs the value to append
inline OID & operator+=(word32 rhs) {m_values.push_back(rhs); return *this;}
/// \brief DER encode this OID
/// \param bt BufferedTransformation object
void DEREncode(BufferedTransformation &bt) const;
/// \brief BER decode an OID
/// \param bt BufferedTransformation object
void BERDecode(BufferedTransformation &bt);
/// \brief BER decode an OID
/// \param bt BufferedTransformation object
/// \throws BERDecodeErr() if decoded value doesn't match an expected OID
/// \details BERDecodeAndCheck() can be used to parse an OID and verify it matches an expected.
/// <pre>
/// BERSequenceDecoder key(bt);
/// ...
/// BERSequenceDecoder algorithm(key);
/// GetAlgorithmID().BERDecodeAndCheck(algorithm);
/// </pre>
void BERDecodeAndCheck(BufferedTransformation &bt) const;
bool Empty() const {
return m_values.empty();
}
const std::vector<word32>& GetValues() const {
return m_values;
}
protected: friend bool operator==(const OID &lhs, const OID &rhs); friend bool operator!=(const OID &lhs, const OID &rhs); friend bool operator<(const OID &lhs, const OID &rhs);
std::vector<word32> m_values;
private: static void EncodeValue(BufferedTransformation &bt, word32 v); static size_t DecodeValue(BufferedTransformation &bt, word32 &v); };
/// \brief ASN.1 encoded object filter class EncodedObjectFilter : public Filter { public: enum Flag {PUT_OBJECTS=1, PUT_MESSANGE_END_AFTER_EACH_OBJECT=2, PUT_MESSANGE_END_AFTER_ALL_OBJECTS=4, PUT_MESSANGE_SERIES_END_AFTER_ALL_OBJECTS=8}; enum State {IDENTIFIER, LENGTH, BODY, TAIL, ALL_DONE} m_state;
virtual ~EncodedObjectFilter() {}
/// \brief Construct an EncodedObjectFilter
/// \param attachment a BufferedTrasformation to attach to this object
/// \param nObjects the number of objects
/// \param flags bitwise OR of EncodedObjectFilter::Flag
EncodedObjectFilter(BufferedTransformation *attachment = NULLPTR, unsigned int nObjects = 1, word32 flags = 0);
/// \brief Input a byte buffer for processing
/// \param inString the byte buffer to process
/// \param length the size of the string, in bytes
void Put(const byte *inString, size_t length);
unsigned int GetNumberOfCompletedObjects() const {return m_nCurrentObject;}
unsigned long GetPositionOfObject(unsigned int i) const {return m_positions[i];}
private: BufferedTransformation & CurrentTarget();
ByteQueue m_queue;
std::vector<unsigned int> m_positions;
lword m_lengthRemaining;
word32 m_nObjects, m_nCurrentObject, m_level, m_flags;
byte m_id;
};
/// \brief BER General Decoder class CRYPTOPP_DLL BERGeneralDecoder : public Store { public: virtual ~BERGeneralDecoder();
explicit BERGeneralDecoder(BufferedTransformation &inQueue, byte asnTag);
explicit BERGeneralDecoder(BERGeneralDecoder &inQueue, byte asnTag);
bool IsDefiniteLength() const {return m_definiteLength;}
lword RemainingLength() const {CRYPTOPP_ASSERT(m_definiteLength); return m_length;}
bool EndReached() const;
byte PeekByte() const;
void CheckByte(byte b);
size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true);
size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const;
// call this to denote end of sequence
void MessageEnd();
protected: BufferedTransformation &m_inQueue; lword m_length; bool m_finished, m_definiteLength;
private: void Init(byte asnTag); void StoreInitialize(const NameValuePairs ¶meters) {CRYPTOPP_UNUSED(parameters); CRYPTOPP_ASSERT(false);} lword ReduceLength(lword delta); };
/// \brief DER General Encoder class CRYPTOPP_DLL DERGeneralEncoder : public ByteQueue { public: virtual ~DERGeneralEncoder();
explicit DERGeneralEncoder(BufferedTransformation &outQueue, byte asnTag = SEQUENCE | CONSTRUCTED);
explicit DERGeneralEncoder(DERGeneralEncoder &outQueue, byte asnTag = SEQUENCE | CONSTRUCTED);
// call this to denote end of sequence
void MessageEnd();
private: BufferedTransformation &m_outQueue; byte m_asnTag; bool m_finished; };
/// \brief BER Sequence Decoder class CRYPTOPP_DLL BERSequenceDecoder : public BERGeneralDecoder { public: explicit BERSequenceDecoder(BufferedTransformation &inQueue, byte asnTag = SEQUENCE | CONSTRUCTED) : BERGeneralDecoder(inQueue, asnTag) {} explicit BERSequenceDecoder(BERSequenceDecoder &inQueue, byte asnTag = SEQUENCE | CONSTRUCTED) : BERGeneralDecoder(inQueue, asnTag) {} };
/// \brief DER Sequence Encoder class CRYPTOPP_DLL DERSequenceEncoder : public DERGeneralEncoder { public: explicit DERSequenceEncoder(BufferedTransformation &outQueue, byte asnTag = SEQUENCE | CONSTRUCTED) : DERGeneralEncoder(outQueue, asnTag) {} explicit DERSequenceEncoder(DERSequenceEncoder &outQueue, byte asnTag = SEQUENCE | CONSTRUCTED) : DERGeneralEncoder(outQueue, asnTag) {} };
/// \brief BER Set Decoder class CRYPTOPP_DLL BERSetDecoder : public BERGeneralDecoder { public: explicit BERSetDecoder(BufferedTransformation &inQueue, byte asnTag = SET | CONSTRUCTED) : BERGeneralDecoder(inQueue, asnTag) {} explicit BERSetDecoder(BERSetDecoder &inQueue, byte asnTag = SET | CONSTRUCTED) : BERGeneralDecoder(inQueue, asnTag) {} };
/// \brief DER Set Encoder class CRYPTOPP_DLL DERSetEncoder : public DERGeneralEncoder { public: explicit DERSetEncoder(BufferedTransformation &outQueue, byte asnTag = SET | CONSTRUCTED) : DERGeneralEncoder(outQueue, asnTag) {} explicit DERSetEncoder(DERSetEncoder &outQueue, byte asnTag = SET | CONSTRUCTED) : DERGeneralEncoder(outQueue, asnTag) {} };
/// \brief Optional data encoder and decoder /// \tparam T class or type template class ASNOptional : public member_ptr { public: /// \brief BER decode optional data /// \param seqDecoder sequence with the optional ASN.1 data /// \param tag ASN.1 tag to match as optional data /// \param mask the mask to apply when matching the tag /// \sa ASNTag and ASNIdFlag void BERDecode(BERSequenceDecoder &seqDecoder, byte tag, byte mask = ~CONSTRUCTED) { byte b; if (seqDecoder.Peek(b) && (b & mask) == tag) reset(new T(seqDecoder)); }
/// \brief DER encode optional data
/// \param out BufferedTransformation object
void DEREncode(BufferedTransformation &out)
{
if (this->get() != NULLPTR)
this->get()->DEREncode(out);
}
};
/// \brief Encode and decode ASN.1 objects with additional information /// \tparam BASE base class or type /// \details Encodes and decodes public keys, private keys and group /// parameters with OID identifying the algorithm or scheme. template class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE ASN1CryptoMaterial : public ASN1Object, public BASE { public: /// \brief DER encode ASN.1 object /// \param bt BufferedTransformation object /// \details Save() will write the OID associated with algorithm or scheme. /// In the case of public and private keys, this function writes the /// subjectPubicKeyInfo and privateKeyInfo parts. void Save(BufferedTransformation &bt) const {BEREncode(bt);}
/// \brief BER decode ASN.1 object
/// \param bt BufferedTransformation object
void Load(BufferedTransformation &bt)
{BERDecode(bt);}
};
/// \brief Encodes and decodes subjectPublicKeyInfo class CRYPTOPP_DLL X509PublicKey : public ASN1CryptoMaterial { public: virtual ~X509PublicKey() {}
void BERDecode(BufferedTransformation &bt);
void DEREncode(BufferedTransformation &bt) const;
/// \brief Retrieves the OID of the algorithm
/// \returns OID of the algorithm
virtual OID GetAlgorithmID() const =0;
virtual bool BERDecodeAlgorithmParameters(BufferedTransformation &bt)
{BERDecodeNull(bt); return false;}
virtual bool DEREncodeAlgorithmParameters(BufferedTransformation &bt) const
{DEREncodeNull(bt); return false;} // see RFC 2459, section 7.3.1
/// decode subjectPublicKey part of subjectPublicKeyInfo, without the BIT STRING header
virtual void BERDecodePublicKey(BufferedTransformation &bt, bool parametersPresent, size_t size) =0;
/// encode subjectPublicKey part of subjectPublicKeyInfo, without the BIT STRING header
virtual void DEREncodePublicKey(BufferedTransformation &bt) const =0;
};
/// \brief Encodes and Decodes privateKeyInfo class CRYPTOPP_DLL PKCS8PrivateKey : public ASN1CryptoMaterial { public: virtual ~PKCS8PrivateKey() {}
void BERDecode(BufferedTransformation &bt);
void DEREncode(BufferedTransformation &bt) const;
/// \brief Retrieves the OID of the algorithm
/// \returns OID of the algorithm
virtual OID GetAlgorithmID() const =0;
virtual bool BERDecodeAlgorithmParameters(BufferedTransformation &bt)
{BERDecodeNull(bt); return false;}
virtual bool DEREncodeAlgorithmParameters(BufferedTransformation &bt) const
{DEREncodeNull(bt); return false;} // see RFC 2459, section 7.3.1
/// decode privateKey part of privateKeyInfo, without the OCTET STRING header
virtual void BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t size) =0;
/// encode privateKey part of privateKeyInfo, without the OCTET STRING header
virtual void DEREncodePrivateKey(BufferedTransformation &bt) const =0;
/// decode optional attributes including context-specific tag
/*! /note default implementation stores attributes to be output in DEREncodeOptionalAttributes */
virtual void BERDecodeOptionalAttributes(BufferedTransformation &bt);
/// encode optional attributes including context-specific tag
virtual void DEREncodeOptionalAttributes(BufferedTransformation &bt) const;
protected: ByteQueue m_optionalAttributes; };
// ********************************************************
/// \brief DER Encode unsigned value /// \tparam T class or type /// \param out BufferedTransformation object /// \param w unsigned value to encode /// \param asnTag the ASN.1 type /// \details DEREncodeUnsigned() can be used with INTEGER, BOOLEAN, and ENUM template size_t DEREncodeUnsigned(BufferedTransformation &out, T w, byte asnTag = INTEGER) { byte buf[sizeof(w)+1]; unsigned int bc; if (asnTag == BOOLEAN) { buf[sizeof(w)] = w ? 0xff : 0; bc = 1; } else { buf[0] = 0; for (unsigned int i=0; i<sizeof(w); i++) buf[i+1] = byte(w >> (sizeof(w)-1-i)*8); bc = sizeof(w); while (bc > 1 && buf[sizeof(w)+1-bc] == 0) --bc; if (buf[sizeof(w)+1-bc] & 0x80) ++bc; } out.Put(asnTag); size_t lengthBytes = DERLengthEncode(out, bc); out.Put(buf+sizeof(w)+1-bc, bc); return 1+lengthBytes+bc; }
/// \brief BER Decode unsigned value /// \tparam T fundamental C++ type /// \param in BufferedTransformation object /// \param w the decoded value /// \param asnTag the ASN.1 type /// \param minValue the minimum expected value /// \param maxValue the maximum expected value /// \throws BERDecodeErr() if the value cannot be parsed or the decoded value is not within range. /// \details DEREncodeUnsigned() can be used with INTEGER, BOOLEAN, and ENUM template void BERDecodeUnsigned(BufferedTransformation &in, T &w, byte asnTag = INTEGER, T minValue = 0, T maxValue = T(0xffffffff)) { byte b; if (!in.Get(b) || b != asnTag) BERDecodeError();
size_t bc;
bool definite = BERLengthDecode(in, bc);
if (!definite)
BERDecodeError();
if (bc > in.MaxRetrievable()) // Issue 346
BERDecodeError();
if (asnTag == BOOLEAN && bc != 1) // X.690, 8.2.1
BERDecodeError();
if ((asnTag == INTEGER || asnTag == ENUMERATED) && bc == 0) // X.690, 8.3.1 and 8.4
BERDecodeError();
SecByteBlock buf(bc);
if (bc != in.Get(buf, bc))
BERDecodeError();
// This consumes leading 0 octets. According to X.690, 8.3.2, it could be non-conforming behavior.
// X.690, 8.3.2 says "the bits of the first octet and bit 8 of the second octet ... (a) shall
// not all be ones and (b) shall not all be zeros ... These rules ensure that an integer value
// is always encoded in the smallest possible number of octet".
// We invented AER (Alternate Encoding Rules), which is more relaxed than BER, CER, and DER.
const byte *ptr = buf;
while (bc > sizeof(w) && *ptr == 0)
{
bc--;
ptr++;
}
if (bc > sizeof(w))
BERDecodeError();
w = 0;
for (unsigned int i=0; i<bc; i++)
w = (w << 8) | ptr[i];
if (w < minValue || w > maxValue)
BERDecodeError();
}
#ifdef CRYPTOPP_DOXYGEN_PROCESSING /// \brief Compare two OIDs for equality /// \param lhs the first OID /// \param rhs the second OID /// \returns true if the OIDs are equal, false otherwise inline bool operator==(const OID &lhs, const OID &rhs); /// \brief Compare two OIDs for inequality /// \param lhs the first OID /// \param rhs the second OID /// \returns true if the OIDs are not equal, false otherwise inline bool operator!=(const OID &lhs, const OID &rhs); /// \brief Compare two OIDs for ordering /// \param lhs the first OID /// \param rhs the second OID /// \returns true if the first OID is less than the second OID, false otherwise /// \details operator<() calls std::lexicographical_compare() on each element in the array of values. inline bool operator<(const OID &lhs, const OID &rhs); /// \brief Append a value to an OID /// \param lhs the OID /// \param rhs the value to append inline OID operator+(const OID &lhs, unsigned long rhs); #else inline bool operator==(const ::CryptoPP::OID &lhs, const ::CryptoPP::OID &rhs) {return lhs.m_values == rhs.m_values;} inline bool operator!=(const ::CryptoPP::OID &lhs, const ::CryptoPP::OID &rhs) {return lhs.m_values != rhs.m_values;} inline bool operator<(const ::CryptoPP::OID &lhs, const ::CryptoPP::OID &rhs) {return std::lexicographical_compare(lhs.m_values.begin(), lhs.m_values.end(), rhs.m_values.begin(), rhs.m_values.end());} inline ::CryptoPP::OID operator+(const ::CryptoPP::OID &lhs, unsigned long rhs) {return ::CryptoPP::OID(lhs)+=rhs;} #endif
NAMESPACE_END
// Issue 340 #if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE
#endif
#endif
//basecode.h======================================================================================================================
// basecode.h - originally written and placed in the public domain by Wei Dai
/// \file /// \brief Base classes for working with encoders and decoders.
#ifndef CRYPTOPP_BASECODE_H #define CRYPTOPP_BASECODE_H
#include "cryptlib.h" #include "filters.h" #include "algparam.h" #include "argnames.h"
NAMESPACE_BEGIN(CryptoPP)
/// \brief Encoder for bases that are a power of 2 class CRYPTOPP_DLL BaseN_Encoder : public Unflushable { public: /// \brief Construct a BaseN_Encoder /// \param attachment a BufferedTransformation to attach to this object BaseN_Encoder(BufferedTransformation *attachment=NULLPTR) : m_alphabet(NULLPTR), m_padding(0), m_bitsPerChar(0) , m_outputBlockSize(0), m_bytePos(0), m_bitPos(0) {Detach(attachment);}
/// \brief Construct a BaseN_Encoder
/// \param alphabet table of ASCII characters to use as the alphabet
/// \param log2base the log<sub>2</sub>base
/// \param attachment a BufferedTransformation to attach to this object
/// \param padding the character to use as padding
/// \pre log2base must be between 1 and 7 inclusive
/// \throws InvalidArgument if log2base is not between 1 and 7
BaseN_Encoder(const byte *alphabet, int log2base, BufferedTransformation *attachment=NULLPTR, int padding=-1)
: m_alphabet(NULLPTR), m_padding(0), m_bitsPerChar(0)
, m_outputBlockSize(0), m_bytePos(0), m_bitPos(0)
{
Detach(attachment);
IsolatedInitialize(MakeParameters(Name::EncodingLookupArray(), alphabet)
(Name::Log2Base(), log2base)
(Name::Pad(), padding != -1)
(Name::PaddingByte(), byte(padding)));
}
void IsolatedInitialize(const NameValuePairs ¶meters);
size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking);
private: const byte *m_alphabet; int m_padding, m_bitsPerChar, m_outputBlockSize; int m_bytePos, m_bitPos; SecByteBlock m_outBuf; };
/// \brief Decoder for bases that are a power of 2 class CRYPTOPP_DLL BaseN_Decoder : public Unflushable { public: /// \brief Construct a BaseN_Decoder /// \param attachment a BufferedTransformation to attach to this object /// \details padding is set to -1, which means use default padding. If not /// required, then the value must be set via IsolatedInitialize(). BaseN_Decoder(BufferedTransformation *attachment=NULLPTR) : m_lookup(NULLPTR), m_bitsPerChar(0) , m_outputBlockSize(0), m_bytePos(0), m_bitPos(0) {Detach(attachment);}
/// \brief Construct a BaseN_Decoder
/// \param lookup table of values
/// \param log2base the log<sub>2</sub>base
/// \param attachment a BufferedTransformation to attach to this object
/// \details log2base is the exponent (like 5 in 2<sup>5</sup>), and not
/// the number of elements (like 32).
/// \details padding is set to -1, which means use default padding. If not
/// required, then the value must be set via IsolatedInitialize().
BaseN_Decoder(const int *lookup, int log2base, BufferedTransformation *attachment=NULLPTR)
: m_lookup(NULLPTR), m_bitsPerChar(0)
, m_outputBlockSize(0), m_bytePos(0), m_bitPos(0)
{
Detach(attachment);
IsolatedInitialize(MakeParameters(Name::DecodingLookupArray(), lookup)(Name::Log2Base(), log2base));
}
void IsolatedInitialize(const NameValuePairs ¶meters);
size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking);
/// \brief Initializes BaseN lookup array
/// \param lookup table of values
/// \param alphabet table of ASCII characters
/// \param base the base for the encoder
/// \param caseInsensitive flag indicating whether the alphabet is case sensitivie
/// \pre COUNTOF(lookup) == 256
/// \pre COUNTOF(alphabet) == base
/// \details Internally, the function sets the first 256 elements in the lookup table to
/// their value from the alphabet array or -1. base is the number of element (like 32),
/// and not an exponent (like 5 in 2<sup>5</sup>)
static void CRYPTOPP_API InitializeDecodingLookupArray(int *lookup, const byte *alphabet, unsigned int base, bool caseInsensitive);
private: const int *m_lookup; int m_bitsPerChar, m_outputBlockSize; int m_bytePos, m_bitPos; SecByteBlock m_outBuf; };
/// \brief Filter that breaks input stream into groups of fixed size class CRYPTOPP_DLL Grouper : public Bufferless { public: /// \brief Construct a Grouper /// \param attachment a BufferedTransformation to attach to this object Grouper(BufferedTransformation *attachment=NULLPTR) : m_groupSize(0), m_counter(0) {Detach(attachment);}
/// \brief Construct a Grouper
/// \param groupSize the size of the grouping
/// \param separator the separator to use between groups
/// \param terminator the terminator appeand after processing
/// \param attachment a BufferedTransformation to attach to this object
Grouper(int groupSize, const std::string &separator, const std::string &terminator, BufferedTransformation *attachment=NULLPTR)
: m_groupSize(0), m_counter(0)
{
Detach(attachment);
IsolatedInitialize(MakeParameters(Name::GroupSize(), groupSize)
(Name::Separator(), ConstByteArrayParameter(separator))
(Name::Terminator(), ConstByteArrayParameter(terminator)));
}
void IsolatedInitialize(const NameValuePairs ¶meters);
size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking);
private: SecByteBlock m_separator, m_terminator; size_t m_groupSize, m_counter; };
NAMESPACE_END
#endif
//channels.h===========================================================================================================
// channels.h - originally written and placed in the public domain by Wei Dai
/// \file channels.h /// \brief Classes for multiple named channels
#ifndef CRYPTOPP_CHANNELS_H #define CRYPTOPP_CHANNELS_H
#include "cryptlib.h" #include "simple.h" #include "smartptr.h" #include "stdcpp.h"
#if CRYPTOPP_MSC_VERSION
#endif
NAMESPACE_BEGIN(CryptoPP)
#if 0 /// Route input on default channel to different and/or multiple channels based on message sequence number class MessageSwitch : public Sink { public: void AddDefaultRoute(BufferedTransformation &destination, const std::string &channel); void AddRoute(unsigned int begin, unsigned int end, BufferedTransformation &destination, const std::string &channel);
void Put(byte inByte);
void Put(const byte *inString, unsigned int length);
void Flush(bool completeFlush, int propagation=-1);
void MessageEnd(int propagation=-1);
void PutMessageEnd(const byte *inString, unsigned int length, int propagation=-1);
void MessageSeriesEnd(int propagation=-1);
private: typedef std::pair<BufferedTransformation *, std::string> Route; struct RangeRoute { RangeRoute(unsigned int begin, unsigned int end, const Route &route) : begin(begin), end(end), route(route) {} bool operator<(const RangeRoute &rhs) const {return begin < rhs.begin;} unsigned int begin, end; Route route; };
typedef std::list<RangeRoute> RouteList;
typedef std::list<Route> DefaultRouteList;
RouteList m_routes;
DefaultRouteList m_defaultRoutes;
unsigned int m_nCurrentMessage;
}; #endif
class ChannelSwitchTypedefs { public: typedef std::pair<BufferedTransformation *, std::string> Route; typedef std::multimap<std::string, Route> RouteMap;
typedef std::pair<BufferedTransformation *, value_ptr<std::string> > DefaultRoute;
typedef std::list<DefaultRoute> DefaultRouteList;
// SunCC workaround: can't use const_iterator here
typedef RouteMap::iterator MapIterator;
typedef DefaultRouteList::iterator ListIterator;
};
class ChannelSwitch;
class ChannelRouteIterator : public ChannelSwitchTypedefs { public: ChannelRouteIterator(ChannelSwitch &cs) : m_cs(cs), m_useDefault(false) {}
void Reset(const std::string &channel);
bool End() const;
void Next();
BufferedTransformation & Destination();
const std::string & Channel();
ChannelSwitch& m_cs;
std::string m_channel;
bool m_useDefault;
MapIterator m_itMapCurrent, m_itMapEnd;
ListIterator m_itListCurrent, m_itListEnd;
protected: // Hide this to see if we break something... ChannelRouteIterator(); };
/// Route input to different and/or multiple channels based on channel ID class CRYPTOPP_DLL ChannelSwitch : public Multichannel, public ChannelSwitchTypedefs { public: ChannelSwitch() : m_it(*this), m_blocked(false) {} ChannelSwitch(BufferedTransformation &destination) : m_it(*this), m_blocked(false) { AddDefaultRoute(destination); } ChannelSwitch(BufferedTransformation &destination, const std::string &outChannel) : m_it(*this), m_blocked(false) { AddDefaultRoute(destination, outChannel); }
void IsolatedInitialize(const NameValuePairs ¶meters=g_nullNameValuePairs);
size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking);
size_t ChannelPutModifiable2(const std::string &channel, byte *begin, size_t length, int messageEnd, bool blocking);
bool ChannelFlush(const std::string &channel, bool completeFlush, int propagation=-1, bool blocking=true);
bool ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1, bool blocking=true);
byte * ChannelCreatePutSpace(const std::string &channel, size_t &size);
void AddDefaultRoute(BufferedTransformation &destination);
void RemoveDefaultRoute(BufferedTransformation &destination);
void AddDefaultRoute(BufferedTransformation &destination, const std::string &outChannel);
void RemoveDefaultRoute(BufferedTransformation &destination, const std::string &outChannel);
void AddRoute(const std::string &inChannel, BufferedTransformation &destination, const std::string &outChannel);
void RemoveRoute(const std::string &inChannel, BufferedTransformation &destination, const std::string &outChannel);
private: RouteMap m_routeMap; DefaultRouteList m_defaultRoutes;
ChannelRouteIterator m_it;
bool m_blocked;
friend class ChannelRouteIterator;
};
NAMESPACE_END
#if CRYPTOPP_MSC_VERSION
#endif
#endif
//config.h=================================================================================================
// config.h - originally written and placed in the public domain by Wei Dai
/// \file config.h /// \brief Library configuration file
#ifndef CRYPTOPP_CONFIG_H #define CRYPTOPP_CONFIG_H
// ***************** Important Settings ********************
// define this if running on a big-endian CPU // big endian will be assumed if CRYPTOPP_LITTLE_ENDIAN is not non-0 #if !defined(CRYPTOPP_LITTLE_ENDIAN) && !defined(CRYPTOPP_BIG_ENDIAN) && (defined(BIG_ENDIAN) || (defined(s390) || defined(s390x) || defined(zarch)) || (defined(m68k) || defined(MC68K)) || defined(__sparc) || defined(sparc) || defined(hppa) || defined(MIPSEB) || defined(ARMEB) || (defined(MWERKS) && !defined(INTEL)))
#endif
// define this if running on a little-endian CPU // big endian will be assumed if CRYPTOPP_LITTLE_ENDIAN is not non-0 #if !defined(CRYPTOPP_BIG_ENDIAN) && !defined(CRYPTOPP_LITTLE_ENDIAN)
#endif
// Sanity checks. Some processors have more than big, little and bi-endian modes. PDP mode, where order results in "4312", should // raise red flags immediately. Additionally, mis-classified machines, like (previosuly) S/390, should raise red flags immediately. #if (CRYPTOPP_BIG_ENDIAN) && defined(GNUC) && defined(BYTE_ORDER) && (BYTE_ORDER != ORDER_BIG_ENDIAN)
#endif #if (CRYPTOPP_LITTLE_ENDIAN) && defined(GNUC) && defined(BYTE_ORDER) && (BYTE_ORDER != ORDER_LITTLE_ENDIAN)
#endif
// Define this if you want to disable all OS-dependent features, // such as sockets and OS-provided random number generators // #define NO_OS_DEPENDENCE
// Define this to use features provided by Microsoft's CryptoAPI. // Currently the only feature used is Windows random number generation. // This macro will be ignored if NO_OS_DEPENDENCE is defined. // #define USE_MS_CRYPTOAPI
// Define this to use features provided by Microsoft's CryptoNG API. // CryptoNG API is available in Vista and above and its cross platform, // including desktop apps and store apps. Currently the only feature // used is Windows random number generation. // This macro will be ignored if NO_OS_DEPENDENCE is defined. // #define USE_MS_CNGAPI
// If the user did not make a choice, then select CryptoNG if // targeting Windows 8 or above. #if !defined(USE_MS_CRYPTOAPI) && !defined(USE_MS_CNGAPI)
if !defined(USING_V110_SDK71) && ((WINVER >= 0x0602 /_WIN32_WINNT_WIN8/) || (_WIN32_WINNT >= 0x0602 /_WIN32_WINNT_WIN8/))
#endif
// Define this to disable ASM, intrinsics and built-ins. The library will be // compiled using C++ only. The library code will not include SSE2 (and // above), NEON, Aarch32, Aarch64, or Altivec (and above). Note the compiler // may use higher ISAs depending on compiler options, but the library will not // explictly use the ISAs. When disabling ASM, it is best to do it from // config.h to ensure the library and all programs share the setting. // #define CRYPTOPP_DISABLE_ASM 1
// https://github.com/weidai11/cryptopp/issues/719 #if defined(native_client)
#endif
// Some Clang and SunCC cannot handle mixed asm with positional arguments, // where the body is Intel style with no prefix and the templates are // AT&T style. Define this is the Makefile misdetects the configuration. // Also see https://bugs.llvm.org/show_bug.cgi?id=39895 . // #define CRYPTOPP_DISABLE_MIXED_ASM 1
// Define CRYPTOPP_NO_CXX11 to avoid C++11 related features shown at the
// end of this file. Some compilers and standard C++ headers advertise C++11
// but they are really just C++03 with some additional C++11 headers and
// non-conforming classes. You might also consider -std=c++03
or
// -std=gnu++03
, but they are required options when building the library
// and all programs. CRYPTOPP_NO_CXX11 is probably easier to manage but it may
// cause -Wterminate warnings under GCC. MSVC++ has a similar warning.
// Also see https://github.com/weidai11/cryptopp/issues/529
// #define CRYPTOPP_NO_CXX11 1
// Define CRYPTOPP_NO_CXX17 to avoid C++17 related features shown at the end of // this file. At the moment it should only affect std::uncaught_exceptions. // #define CRYPTOPP_NO_CXX17 1
// CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS is no longer honored. It // was removed at https://github.com/weidai11/cryptopp/issues/682 // #define CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS 1
// ***************** Less Important Settings ***************
// Library version macro. Since this macro is in a header, it reflects // the version of the library the headers came from. It is not // necessarily the version of the library built as a shared object if // versions are inadvertently mixed and matched. #define CRYPTOPP_MAJOR 8 #define CRYPTOPP_MINOR 2 #define CRYPTOPP_REVISION 0 #define CRYPTOPP_VERSION 820
// Define this if you want to set a prefix for TestData/ and TestVectors/ // Be sure to add the trailing slash since its simple concatenation. // After https://github.com/weidai11/cryptopp/issues/760 the library // should find the test vectors and data without much effort. It // will search in "./" and "$ORIGIN/../share/cryptopp" automatically. #ifndef CRYPTOPP_DATA_DIR
#endif
// Define this to disable the test suite from searching for test // vectors and data in "./" and "$ORIGIN/../share/cryptopp". The // library will still search in CRYPTOPP_DATA_DIR, regardless. // Some distros may want to disable this feature. Also see // https://github.com/weidai11/cryptopp/issues/760 // #ifndef CRYPTOPP_DISABLE_DATA_DIR_SEARCH // # define CRYPTOPP_DISABLE_DATA_DIR_SEARCH // #endif
// Define this if you want or need the library's memcpy_s and memmove_s. // See http://github.com/weidai11/cryptopp/issues/28. // #if !defined(CRYPTOPP_WANT_SECURE_LIB) // # define CRYPTOPP_WANT_SECURE_LIB // #endif
// File system code to write to GZIP archive. // http://www.gzip.org/format.txt #if !defined(GZIP_OS_CODE)
#endif
// Try this if your CPU has 256K internal cache or a slow multiply instruction // and you want a (possibly) faster IDEA implementation using log tables // #define IDEA_LARGECACHE
// Define this if, for the linear congruential RNG, you want to use // the original constants as specified in S.K. Park and K.W. Miller's // CACM paper. // #define LCRNG_ORIGINAL_NUMBERS
// Define this if you want Integer's operator<< to honor std::showbase (and // std::noshowbase). If defined, Integer will use a suffix of 'b', 'o', 'h' // or '.' (the last for decimal) when std::showbase is in effect. If // std::noshowbase is set, then the suffix is not added to the Integer. If // not defined, existing behavior is preserved and Integer will use a suffix // of 'b', 'o', 'h' or '.' (the last for decimal). // #define CRYPTOPP_USE_STD_SHOWBASE
// Define this if ARMv8 shifts are slow. ARM Cortex-A53 and Cortex-A57 shift // operation perform poorly, so NEON and ASIMD code that relies on shifts // or rotates often performs worse than C/C++ code. Also see // http://github.com/weidai11/cryptopp/issues/367. #define CRYPTOPP_SLOW_ARMV8_SHIFT 1
// Define this if you want to decouple AlgorithmParameters and Integer // The decoupling should make it easier for the linker to remove Integer // related code for those who do not need Integer, and avoid a potential // race during AssignIntToInteger pointer initialization. Also // see http://github.com/weidai11/cryptopp/issues/389. // #define CRYPTOPP_NO_ASSIGN_TO_INTEGER
// set the name of Rijndael cipher, was "Rijndael" before version 5.3 #define CRYPTOPP_RIJNDAEL_NAME "AES"
// CRYPTOPP_DEBUG enables the library's CRYPTOPP_ASSERT. CRYPTOPP_ASSERT // raises a SIGTRAP (Unix) or calls DebugBreak() (Windows). CRYPTOPP_ASSERT // is only in effect when CRYPTOPP_DEBUG, DEBUG or _DEBUG is defined. Unlike // Posix assert, CRYPTOPP_ASSERT is not affected by NDEBUG (or failure to // define it). // Also see http://github.com/weidai11/cryptopp/issues/277, CVE-2016-7420 #if (defined(DEBUG) || defined(_DEBUG)) && !defined(CRYPTOPP_DEBUG)
#endif
// ***************** Important Settings Again ******************** // But the defaults should be ok.
// namespace support is now required #ifdef NO_NAMESPACE
#endif
#ifdef CRYPTOPP_DOXYGEN_PROCESSING // Document the namespce exists. Put it here before CryptoPP is undefined below. /// \namespace CryptoPP /// \brief Crypto++ library namespace /// \details Nearly all classes are located in the CryptoPP namespace. Within /// the namespace, there are two additional namespaces. ///
-
///
- Name - namespace for names used with \p NameValuePairs and documented in argnames.h ///
- NaCl - namespace for NaCl library functions like crypto_box, crypto_box_open, crypto_sign, and crypto_sign_open ///
- Donna - namespace for curve25519 library operations. The name was selected due to use of Adam Langley's curve25519-donna. ///
- Test - namespace for testing and benchmarks classes ///
- Weak - namespace for weak and wounded algorithms, like ARC4, MD5 and Pananma ///
// Avoid putting "CryptoPP::" in front of everything in Doxygen output
// Get Doxygen to generate better documentation for these typedefs
// Make "protected" "private" so the functions and members are not documented
#else
#endif #define ANONYMOUS_NAMESPACE_BEGIN namespace { #define ANONYMOUS_NAMESPACE_END } #define USING_NAMESPACE(x) using namespace x; #define DOCUMENTED_NAMESPACE_BEGIN(x) namespace x { #define DOCUMENTED_NAMESPACE_END }
// Originally in global namespace to avoid ambiguity with other byte typedefs. // Moved to Crypto++ namespace due to C++17, std::byte and potential compile problems. Also see // http://www.cryptopp.com/wiki/std::byte and http://github.com/weidai11/cryptopp/issues/442 // typedef unsigned char byte; #define CRYPTOPP_NO_GLOBAL_BYTE 1
NAMESPACE_BEGIN(CryptoPP)
// Signed words added at Issue 609 for early versions of and Visual Studio and // the NaCl gear. Also see https://github.com/weidai11/cryptopp/issues/609.
typedef unsigned char byte; typedef unsigned short word16; typedef unsigned int word32;
typedef signed char sbyte; typedef signed short sword16; typedef signed int sword32;
#if defined(_MSC_VER) || defined(BORLANDC) typedef signed __int64 sword64; typedef unsigned __int64 word64; #define SW64LIT(x) x##i64 #define W64LIT(x) x##ui64 #elif (_LP64 || LP64) typedef signed long sword64; typedef unsigned long word64; #define SW64LIT(x) x##L #define W64LIT(x) x##UL #else typedef signed long long sword64; typedef unsigned long long word64; #define SW64LIT(x) x##LL #define W64LIT(x) x##ULL #endif
// define large word type, used for file offsets and such typedef word64 lword; const lword LWORD_MAX = W64LIT(0xffffffffffffffff);
// It is OK to remove the hard stop below, but you are on your own. // After building the library be sure to run self tests described // https://www.cryptopp.com/wiki/Release_Process#Self_Tests // Some relevant bug reports can be found at: // * Clang: http://github.com/weidai11/cryptopp/issues/147 // * Native Client: https://github.com/weidai11/cryptopp/issues/719 #if (defined(_MSC_VER) && defined(clang))
#endif
#ifdef GNUC #define CRYPTOPP_GCC_VERSION (GNUC * 10000 + GNUC_MINOR * 100 + GNUC_PATCHLEVEL) #endif
#if defined(xlc) || defined(xlC) #define CRYPTOPP_XLC_VERSION ((xlC / 256) * 10000 + (xlC % 256) * 100) #endif
// Apple and LLVM's Clang. Apple Clang version 7.0 roughly equals LLVM Clang version 3.7 #if defined(clang) && defined(apple_build_version) #define CRYPTOPP_APPLE_CLANG_VERSION (clang_major * 10000 + clang_minor * 100 + clang_patchlevel) #elif defined(clang) #define CRYPTOPP_LLVM_CLANG_VERSION (clang_major * 10000 + clang_minor * 100 + clang_patchlevel) #endif
#ifdef _MSC_VER #define CRYPTOPP_MSC_VERSION (_MSC_VER) #endif
// Need GCC 4.6/Clang 1.7/Apple Clang 2.0 or above due to "GCC diagnostic {push|pop}" #if (CRYPTOPP_GCC_VERSION >= 40600) || (CRYPTOPP_LLVM_CLANG_VERSION >= 10700) || (CRYPTOPP_APPLE_CLANG_VERSION >= 20000) #define CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE 1 #endif
// define hword, word, and dword. these are used for multiprecision integer arithmetic // Intel compiler won't have _umul128 until version 10.0. See http://softwarecommunity.intel.com/isn/Community/en-US/forums/thread/30231625.aspx #if (defined(_MSC_VER) && (!defined(__INTEL_COMPILER) || __INTEL_COMPILER >= 1000) && (defined(_M_X64) || defined(_M_IA64))) || (defined(__DECCXX) && defined(alpha)) || (defined(__INTEL_COMPILER) && defined(x86_64)) || (defined(__SUNPRO_CC) && defined(x86_64)) typedef word32 hword; typedef word64 word; #else #define CRYPTOPP_NATIVE_DWORD_AVAILABLE 1 #if defined(alpha) || defined(ia64) || defined(_ARCH_PPC64) || defined(x86_64) || defined(__mips64) || defined(sparc64) #if ((CRYPTOPP_GCC_VERSION >= 30400) || (CRYPTOPP_LLVM_CLANG_VERSION >= 30000) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40300)) && (SIZEOF_INT128 >= 16) // GCC 4.0.1 on MacOS X is missing __umodti3 and __udivti3 // GCC 4.8.3 and bad uint128_t ops on PPC64/POWER7 (Issue 421) // mode(TI) division broken on amd64 with GCC earlier than GCC 3.4 typedef word32 hword; typedef word64 word; typedef __uint128_t dword; typedef __uint128_t word128; #define CRYPTOPP_WORD128_AVAILABLE 1 #else // if we're here, it means we're on a 64-bit CPU but we don't have a way to obtain 128-bit multiplication results typedef word16 hword; typedef word32 word; typedef word64 dword; #endif #else // being here means the native register size is probably 32 bits or less #define CRYPTOPP_BOOL_SLOW_WORD64 1 typedef word16 hword; typedef word32 word; typedef word64 dword; #endif #endif #ifndef CRYPTOPP_BOOL_SLOW_WORD64 #define CRYPTOPP_BOOL_SLOW_WORD64 0 #endif
const unsigned int WORD_SIZE = sizeof(word); const unsigned int WORD_BITS = WORD_SIZE * 8;
NAMESPACE_END
#ifndef CRYPTOPP_L1_CACHE_LINE_SIZE // This should be a lower bound on the L1 cache line size. It's used for defense against timing attacks. // Also see http://stackoverflow.com/questions/794632/programmatically-get-the-cache-line-size. #if defined(_M_X64) || defined(x86_64) || defined(arm64) || defined(aarch64) || defined(powerpc64) || defined(_ARCH_PPC64) #define CRYPTOPP_L1_CACHE_LINE_SIZE 64 #else // L1 cache line size is 32 on Pentium III and earlier #define CRYPTOPP_L1_CACHE_LINE_SIZE 32 #endif #endif
// Sun Studio Express 3 (December 2006) provides GCC-style attributes. // IBM XL C/C++ alignment modifier per Optimization Guide, pp. 19-20. // __IBM_ATTRIBUTES per XLC 12.1 AIX Compiler Manual, p. 473. // CRYPTOPP_ALIGN_DATA may not be reliable on AIX. #ifndef CRYPTOPP_ALIGN_DATA #if defined(_MSC_VER) #define CRYPTOPP_ALIGN_DATA(x) __declspec(align(x)) #elif defined(GNUC) || (__SUNPRO_CC >= 0x5100) #define CRYPTOPP_ALIGN_DATA(x) attribute((aligned(x))) #elif defined(xlc) || defined(xlC) #define CRYPTOPP_ALIGN_DATA(x) attribute((aligned(x))) #else #define CRYPTOPP_ALIGN_DATA(x) #endif #endif
// The section attribute attempts to initialize CPU flags to avoid Valgrind findings above -O1 #if ((defined(MACH) && defined(APPLE)) && ((CRYPTOPP_LLVM_CLANG_VERSION >= 30600) || (CRYPTOPP_APPLE_CLANG_VERSION >= 70100) || (CRYPTOPP_GCC_VERSION >= 40300))) #define CRYPTOPP_SECTION_INIT attribute((section ("__DATA,__data"))) #elif (defined(ELF) && (CRYPTOPP_GCC_VERSION >= 40300)) #define CRYPTOPP_SECTION_INIT attribute((section ("nocommon"))) #elif defined(ELF) && (defined(xlC) || defined(ibmxl)) #define CRYPTOPP_SECTION_INIT attribute((section ("nocommon"))) #else #define CRYPTOPP_SECTION_INIT #endif
#if defined(_MSC_VER) || defined(__fastcall) #define CRYPTOPP_FASTCALL __fastcall #else #define CRYPTOPP_FASTCALL #endif
#ifdef _MSC_VER #define CRYPTOPP_NO_VTABLE __declspec(novtable) #else #define CRYPTOPP_NO_VTABLE #endif
#ifdef _MSC_VER // 4127: conditional expression is constant // 4512: assignment operator not generated // 4661: no suitable definition provided for explicit template instantiation request // 4910: '__declspec(dllexport)' and 'extern' are incompatible on an explicit instantiation
// Security related, possible defects
// http://blogs.msdn.com/b/vcblog/archive/2010/12/14/off-by-default-compiler-warnings-in-visual-c.aspx
#endif
#ifdef BORLANDC // 8037: non-const function called for const object. needed to work around BCB2006 bug
#endif
// [GCC Bug 53431] "C++ preprocessor ignores #pragma GCC diagnostic". Clang honors it. #if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE
#endif
// You may need to force include a C++ header on Android when using STLPort to ensure // _STLPORT_VERSION is defined: CXXFLAGS="-DNDEBUG -g2 -O2 -std=c++11 -include iosfwd" // TODO: Figure out C++17 and lack of std::uncaught_exception #if (defined(_MSC_VER) && _MSC_VER <= 1300) || defined(MWERKS) || (defined(_STLPORT_VERSION) && ((_STLPORT_VERSION < 0x450) || defined(_STLP_NO_UNCAUGHT_EXCEPT_SUPPORT))) #define CRYPTOPP_DISABLE_UNCAUGHT_EXCEPTION #endif
#ifndef CRYPTOPP_DISABLE_UNCAUGHT_EXCEPTION #define CRYPTOPP_UNCAUGHT_EXCEPTION_AVAILABLE #endif
// ***************** Platform and CPU features ********************
// Linux provides X32, which is 32-bit integers, longs and pointers on x86_64 // using the full x86_64 register set. Detect via ILP32 // (http://wiki.debian.org/X32Port). However, ILP32 shows up in more places // than the System V ABI specs calls out, like on some Solaris installations // and just about any 32-bit system with Clang. #if (defined(ILP32) || defined(_ILP32)) && defined(x86_64) #define CRYPTOPP_BOOL_X32 1 #endif
// see http://predef.sourceforge.net/prearch.html #if (defined(_M_IX86) || defined(i386) || defined(__i386) || defined(X86) || defined(I86) || defined(INTEL)) && !CRYPTOPP_BOOL_X32 #define CRYPTOPP_BOOL_X86 1 #endif
#if (defined(_M_X64) || defined(x86_64)) && !CRYPTOPP_BOOL_X32 #define CRYPTOPP_BOOL_X64 1 #endif
// Undo the ASM related defines due to X32. #if CRYPTOPP_BOOL_X32
#endif
// Microsoft added ARM64 define December 2017. #if defined(arm64) || defined(aarch32) || defined(aarch64) || defined(_M_ARM64) #define CRYPTOPP_BOOL_ARMV8 1 #elif defined(arm) || defined(_M_ARM) #define CRYPTOPP_BOOL_ARM32 1 #endif
// AltiVec and Power8 crypto #if defined(ppc64) || defined(powerpc64) || defined(_ARCH_PPC64) #define CRYPTOPP_BOOL_PPC64 1 #elif defined(powerpc) || defined(_ARCH_PPC) #define CRYPTOPP_BOOL_PPC32 1 #endif
// And MIPS. TODO: finish these defines #if defined(mips64) #define CRYPTOPP_BOOL_MIPS64 1 #elif defined(mips) #define CRYPTOPP_BOOL_MIPS32 1 #endif
#if defined(_MSC_VER) || defined(BORLANDC)
#else
#endif
// ***************** IA32 CPU features ********************
#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
// Apple Clang prior to 5.0 cannot handle SSE2 #if defined(CRYPTOPP_APPLE_CLANG_VERSION) && (CRYPTOPP_APPLE_CLANG_VERSION < 50000)
#endif
// Sun Studio 12.1 provides GCC inline assembly // http://blogs.oracle.com/x86be/entry/gcc_style_asm_inlining_support #if !defined(CRYPTOPP_DISABLE_ASM) && defined(__SUNPRO_CC) && (__SUNPRO_CC < 0x5100)
#endif
#if !defined(CRYPTOPP_DISABLE_ASM) && ((defined(_MSC_VER) && defined(_M_IX86)) || (defined(GNUC) && (defined(i386) || defined(x86_64)))) // C++Builder 2010 does not allow "call label" where label is defined within inline assembly #define CRYPTOPP_X86_ASM_AVAILABLE 1
#if !defined(CRYPTOPP_DISABLE_SSE2) && (defined(_MSC_VER) || CRYPTOPP_GCC_VERSION >= 30300 || defined(__SSE2__))
#define CRYPTOPP_SSE2_ASM_AVAILABLE 1
#endif
#if !defined(CRYPTOPP_DISABLE_SSSE3) && (_MSC_VER >= 1500 || CRYPTOPP_GCC_VERSION >= 40300 || defined(__SSSE3__))
#define CRYPTOPP_SSSE3_ASM_AVAILABLE 1
#endif
#endif
#if !defined(CRYPTOPP_DISABLE_ASM) && defined(_MSC_VER) && defined(_M_X64) #define CRYPTOPP_X64_MASM_AVAILABLE 1 #endif
#if !defined(CRYPTOPP_DISABLE_ASM) && defined(GNUC) && defined(x86_64) #define CRYPTOPP_X64_ASM_AVAILABLE 1 #endif
// 32-bit SunCC does not enable SSE2 by default. #if !defined(CRYPTOPP_DISABLE_ASM) && (defined(_MSC_VER) || CRYPTOPP_GCC_VERSION >= 30300 || defined(SSE2) || (__SUNPRO_CC >= 0x5100)) #define CRYPTOPP_SSE2_INTRIN_AVAILABLE 1 #endif
#if !defined(CRYPTOPP_DISABLE_ASM) && !defined(CRYPTOPP_DISABLE_SSSE3)
(CRYPTOPP_GCC_VERSION >= 40300) || (__INTEL_COMPILER >= 1000) || (__SUNPRO_CC >= 0x5110) || \
(CRYPTOPP_LLVM_CLANG_VERSION >= 20300) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40000)
#define CRYPTOPP_SSSE3_AVAILABLE 1
#endif
// Intrinsics availible in GCC 4.3 (http://gcc.gnu.org/gcc-4.3/changes.html) and
// MSVC 2008 (http://msdn.microsoft.com/en-us/library/bb892950%28v=vs.90%29.aspx)
// SunCC could generate SSE4 at 12.1, but the intrinsics are missing until 12.4.
#if !defined(CRYPTOPP_DISABLE_SSE4) && defined(CRYPTOPP_SSSE3_AVAILABLE) &&
(defined(SSE4_1) || (CRYPTOPP_MSC_VERSION >= 1500) ||
(CRYPTOPP_GCC_VERSION >= 40300) || (__INTEL_COMPILER >= 1000) || (__SUNPRO_CC >= 0x5110) ||
(CRYPTOPP_LLVM_CLANG_VERSION >= 20300) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40000))
#define CRYPTOPP_SSE41_AVAILABLE 1
#endif
#if !defined(CRYPTOPP_DISABLE_SSE4) && defined(CRYPTOPP_SSSE3_AVAILABLE) &&
(defined(SSE4_2) || (CRYPTOPP_MSC_VERSION >= 1500) || (__SUNPRO_CC >= 0x5110) ||
(CRYPTOPP_GCC_VERSION >= 40300) || (__INTEL_COMPILER >= 1000) ||
(CRYPTOPP_LLVM_CLANG_VERSION >= 20300) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40000))
#define CRYPTOPP_SSE42_AVAILABLE 1
#endif
// Couple to CRYPTOPP_DISABLE_AESNI, but use CRYPTOPP_CLMUL_AVAILABLE so we can selectively // disable for misbehaving platofrms and compilers, like Solaris or some Clang. #if defined(CRYPTOPP_DISABLE_AESNI) #define CRYPTOPP_DISABLE_CLMUL 1 #endif
// Requires Sun Studio 12.3 (SunCC 0x5120) in theory.
#if !defined(CRYPTOPP_DISABLE_ASM) && !defined(CRYPTOPP_DISABLE_CLMUL) && defined(CRYPTOPP_SSE42_AVAILABLE) &&
(defined(PCLMUL) || (_MSC_FULL_VER >= 150030729) || (__SUNPRO_CC >= 0x5120) ||
(CRYPTOPP_GCC_VERSION >= 40300) || (__INTEL_COMPILER >= 1110) ||
(CRYPTOPP_LLVM_CLANG_VERSION >= 30200) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40300))
#define CRYPTOPP_CLMUL_AVAILABLE 1
#endif
// Requires Sun Studio 12.3 (SunCC 0x5120)
#if !defined(CRYPTOPP_DISABLE_ASM) && !defined(CRYPTOPP_DISABLE_AESNI) && defined(CRYPTOPP_SSE42_AVAILABLE) &&
(defined(AES) || (_MSC_FULL_VER >= 150030729) || (__SUNPRO_CC >= 0x5120) ||
(CRYPTOPP_GCC_VERSION >= 40300) || (__INTEL_COMPILER >= 1110) ||
(CRYPTOPP_LLVM_CLANG_VERSION >= 30200) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40300))
#define CRYPTOPP_AESNI_AVAILABLE 1
#endif
// Requires Binutils 2.24
#if !defined(CRYPTOPP_DISABLE_AVX) && defined(CRYPTOPP_SSE42_AVAILABLE) &&
(defined(AVX2) || (CRYPTOPP_MSC_VERSION >= 1800) || (__SUNPRO_CC >= 0x5130) ||
(CRYPTOPP_GCC_VERSION >= 40700) || (__INTEL_COMPILER >= 1400) ||
(CRYPTOPP_LLVM_CLANG_VERSION >= 30100) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40600))
#define CRYPTOPP_AVX_AVAILABLE 1
#endif
// Requires Binutils 2.24
#if !defined(CRYPTOPP_DISABLE_AVX2) && defined(CRYPTOPP_AVX_AVAILABLE) &&
(defined(AVX2) || (CRYPTOPP_MSC_VERSION >= 1800) || (__SUNPRO_CC >= 0x5130) ||
(CRYPTOPP_GCC_VERSION >= 40900) || (__INTEL_COMPILER >= 1400) ||
(CRYPTOPP_LLVM_CLANG_VERSION >= 30100) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40600))
#define CRYPTOPP_AVX2_AVAILABLE 1
#endif
// Guessing at SHA for SunCC. Its not in Sun Studio 12.6. Also see
// http://stackoverflow.com/questions/45872180/which-xarch-for-sha-extensions-on-solaris
#if !defined(CRYPTOPP_DISABLE_ASM) && !defined(CRYPTOPP_DISABLE_SHANI) && defined(CRYPTOPP_SSE42_AVAILABLE) &&
(defined(SHA) || (CRYPTOPP_MSC_VERSION >= 1900) || (__SUNPRO_CC >= 0x5160) ||
(CRYPTOPP_GCC_VERSION >= 40900) || (__INTEL_COMPILER >= 1300) ||
(CRYPTOPP_LLVM_CLANG_VERSION >= 30400) || (CRYPTOPP_APPLE_CLANG_VERSION >= 50100))
#define CRYPTOPP_SHANI_AVAILABLE 1
#endif
// Fixup Android and SSE, Crypto. It may be enabled based on compiler version. #if (defined(ANDROID) || defined(ANDROID))
#endif
// Fixup for SunCC 12.1-12.4. Bad code generation in AES_Encrypt and friends. #if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x5130)
#endif
// Fixup for SunCC 12.1-12.6. Compiler crash on GCM_Reduce_CLMUL and friends. // http://github.com/weidai11/cryptopp/issues/226 #if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x5150)
#endif
#endif // X86, X32, X64
// ***************** ARM CPU features ********************
#if (CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARMV8)
// We don't have an ARM big endian test rig. Disable // ARM-BE ASM and instrinsics until we can test it. #if (CRYPTOPP_BIG_ENDIAN)
#endif
// Requires ARMv7 and ACLE 1.0. -march=armv7-a or above must be present // Requires GCC 4.3, Clang 2.8 or Visual Studio 2012 // Do not use APPLE_CLANG_VERSION; use __ARM_FEATURE_XXX instead. #if !defined(CRYPTOPP_ARM_NEON_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ASM)
(CRYPTOPP_MSC_VERSION >= 1700)
#endif
// ARMv8 and ASIMD. -march=armv8-a or above must be present // Requires GCC 4.8, Clang 3.3 or Visual Studio 2017 // Do not use APPLE_CLANG_VERSION; use __ARM_FEATURE_XXX instead. #if !defined(CRYPTOPP_ARM_ASIMD_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ASM)
(CRYPTOPP_GCC_VERSION >= 40800) || (CRYPTOPP_CLANG_VERSION >= 30300) || \
(CRYPTOPP_MSC_VERSION >= 1916)
#endif
// ARMv8 and ASIMD. -march=armv8-a+crc or above must be present // Requires GCC 4.8, Clang 3.3 or Visual Studio 2017 // Do not use APPLE_CLANG_VERSION; use __ARM_FEATURE_XXX instead. #if !defined(CRYPTOPP_ARM_CRC32_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ASM)
(CRYPTOPP_CLANG_VERSION >= 30300) || (CRYPTOPP_MSC_VERSION >= 1916)
#endif
// ARMv8 and ASIMD. -march=armv8-a+crypto or above must be present // Requires GCC 4.8, Clang 3.3 or Visual Studio 2017 // Do not use APPLE_CLANG_VERSION; use __ARM_FEATURE_XXX instead. #if !defined(CRYPTOPP_ARM_PMULL_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ASM)
(CRYPTOPP_CLANG_VERSION >= 30300) || (CRYPTOPP_MSC_VERSION >= 1916)
#endif
// ARMv8 and AES. -march=armv8-a+crypto or above must be present // Requires GCC 4.8, Clang 3.3 or Visual Studio 2017 // Do not use APPLE_CLANG_VERSION; use __ARM_FEATURE_XXX instead. #if !defined(CRYPTOPP_ARM_AES_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ASM)
(CRYPTOPP_CLANG_VERSION >= 30300) || (CRYPTOPP_MSC_VERSION >= 1910)
#endif
// ARMv8 and SHA-1, SHA-256. -march=armv8-a+crypto or above must be present // Requires GCC 4.8, Clang 3.3 or Visual Studio 2017 // Do not use APPLE_CLANG_VERSION; use __ARM_FEATURE_XXX instead. #if !defined(CRYPTOPP_ARM_SHA_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ASM)
(CRYPTOPP_CLANG_VERSION >= 30300) || (CRYPTOPP_MSC_VERSION >= 1916)
#endif
// ARMv8 and SHA-512, SHA-3. -march=armv8.4-a+crypto or above must be present // Requires GCC 8.0, Clang 6.0 or Visual Studio 2021??? // Do not use APPLE_CLANG_VERSION; use __ARM_FEATURE_XXX instead. #if !defined(CRYPTOPP_ARM_SHA_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ASM)
(CRYPTOPP_MSC_VERSION >= 5000)
#endif
// ARMv8 and SM3, SM4. -march=armv8.4-a+crypto or above must be present // Requires GCC 8.0, Clang 6.0 or Visual Studio 2021??? // Do not use APPLE_CLANG_VERSION; use __ARM_FEATURE_XXX instead. #if !defined(CRYPTOPP_ARM_SM3_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ASM)
(CRYPTOPP_MSC_VERSION >= 5000)
#endif
// Limit the <arm_acle.h> include. #if !defined(CRYPTOPP_ARM_ACLE_AVAILABLE)
#endif
// Fixup Apple Clang and PMULL. Apple defines __ARM_FEATURE_CRYPTO for Xcode 6 // but does not provide PMULL. TODO: determine when PMULL is available. #if defined(CRYPTOPP_APPLE_CLANG_VERSION) && (CRYPTOPP_APPLE_CLANG_VERSION < 70000)
#endif
// Fixup Android and CRC32. It may be enabled based on compiler version. #if (defined(ANDROID) || defined(ANDROID)) && !defined(__ARM_FEATURE_CRC32)
#endif
// Fixup Android and Crypto. It may be enabled based on compiler version. #if (defined(ANDROID) || defined(ANDROID)) && !defined(__ARM_FEATURE_CRYPTO)
#endif
// Cryptogams offers an ARM asm AES implementation. Crypto++ does // not provide an asm implementation. The Cryptogams implementation // is about 2x faster than C/C++. Define this to use the Cryptogams // AES implementation on GNU Linux systems. When defined, Crypto++ // will use aes_armv4.S. LLVM miscompiles aes_armv4.S so disable // under Clang. See https://bugs.llvm.org/show_bug.cgi?id=38133. #if !defined(CRYPTOPP_DISABLE_ASM) && defined(arm)
#endif
#endif // ARM32, ARM64
// ***************** AltiVec and Power8 ********************
#if (CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64)
#if defined(CRYPTOPP_DISABLE_ALTIVEC) || defined(CRYPTOPP_DISABLE_ASM)
#endif
// An old Apple G5 with GCC 4.01 has AltiVec, but its only Power4 or so. #if !defined(CRYPTOPP_ALTIVEC_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ALTIVEC)
(CRYPTOPP_XLC_VERSION >= 100000) || (CRYPTOPP_GCC_VERSION >= 40001) || \
(CRYPTOPP_CLANG_VERSION >= 20900)
#endif
// We need Power7 for unaligned loads and stores #if !defined(CRYPTOPP_POWER7_AVAILABLE) && !defined(CRYPTOPP_DISABLE_POWER7) && defined(CRYPTOPP_ALTIVEC_AVAILABLE)
(CRYPTOPP_GCC_VERSION >= 40100) || (CRYPTOPP_CLANG_VERSION >= 30100)
#endif
// We need Power8 for in-core crypto and 64-bit vector types #if !defined(CRYPTOPP_POWER8_AVAILABLE) && !defined(CRYPTOPP_DISABLE_POWER8) && defined(CRYPTOPP_POWER7_AVAILABLE)
(CRYPTOPP_GCC_VERSION >= 40800) || (CRYPTOPP_CLANG_VERSION >= 70000)
#endif
// Power9 for random numbers #if !defined(CRYPTOPP_POWER9_AVAILABLE) && !defined(CRYPTOPP_DISABLE_POWER9) && defined(CRYPTOPP_POWER8_AVAILABLE)
(CRYPTOPP_GCC_VERSION >= 70000) || (CRYPTOPP_CLANG_VERSION >= 80000)
#endif
#if !defined(CRYPTOPP_POWER8_AES_AVAILABLE) && !defined(CRYPTOPP_DISABLE_POWER8_AES) && defined(CRYPTOPP_POWER8_AVAILABLE)
(CRYPTOPP_GCC_VERSION >= 40800) || (CRYPTOPP_CLANG_VERSION >= 70000)
//# define CRYPTOPP_POWER8_CRC_AVAILABLE 1
#endif
#endif // PPC32, PPC64
// ***************** Miscellaneous ********************
// Nearly all Intel's and AMD's have SSE. Enable it independent of SSE ASM and intrinscs #if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64) && !defined(CRYPTOPP_DISABLE_ASM) #define CRYPTOPP_BOOL_ALIGN16 1 #else #define CRYPTOPP_BOOL_ALIGN16 0 #endif
// How to allocate 16-byte aligned memory (for SSE2) // posix_memalign see https://forum.kde.org/viewtopic.php?p=66274 #if defined(_MSC_VER) #define CRYPTOPP_MM_MALLOC_AVAILABLE #elif defined(linux) || defined(sun) || defined(CYGWIN) #define CRYPTOPP_MEMALIGN_AVAILABLE #elif defined(APPLE) || defined(NetBSD) || defined(OpenBSD) || defined(DragonFly) #define CRYPTOPP_MALLOC_ALIGNMENT_IS_16 #elif (defined(_GNU_SOURCE) || ((_XOPEN_SOURCE + 0) >= 600)) && (_POSIX_ADVISORY_INFO > 0) #define CRYPTOPP_POSIX_MEMALIGN_AVAILABLE #else #define CRYPTOPP_NO_ALIGNED_ALLOC #endif
// how to disable inlining #if defined(_MSC_VER)
#elif defined(xlc) || defined(xlC) || defined(ibmxl)
#elif defined(GNUC)
#else
#endif
// How to declare class constants #if defined(CRYPTOPP_DOXYGEN_PROCESSING) || defined(BORLANDC)
#else
#endif
// How to disable CPU feature probing. We determine machine // capabilities by performing an os/platform query first, // like getauxv(). If the query fails, we move onto a // cpu probe. The cpu probe tries to exeute an instruction // and then catches a SIGILL on Linux or the exception // EXCEPTION_ILLEGAL_INSTRUCTION on Windows. Some OSes // fail to hangle a SIGILL gracefully, like Apple OSes. Apple // machines corrupt memory and variables around the probe. #if defined(APPLE)
#endif
// ***************** Initialization and Constructor priorities ********************
// CRYPTOPP_INIT_PRIORITY attempts to manage initialization of C++ static objects. // Under GCC, the library uses init_priority attribute in the range // [CRYPTOPP_INIT_PRIORITY, CRYPTOPP_INIT_PRIORITY+100]. Under Windows, // CRYPTOPP_INIT_PRIORITY enlists "#pragma init_seg(lib)". The platforms // with gaps are Apple and Sun because they require linker scripts. Apple and // Sun will use the library's Singletons to initialize and acquire resources. // Also see http://cryptopp.com/wiki/Static_Initialization_Order_Fiasco #ifndef CRYPTOPP_INIT_PRIORITY
#endif
// CRYPTOPP_USER_PRIORITY is for other libraries and user code that is using Crypto++ // and managing C++ static object creation. It is guaranteed not to conflict with // values used by (or would be used by) the Crypto++ library. #ifndef CRYPTOPP_USER_PRIORITY
#endif
// Most platforms allow us to specify when to create C++ objects. Apple and Sun do not. #if (CRYPTOPP_INIT_PRIORITY > 0) && !(defined(NO_OS_DEPENDENCE) || defined(APPLE) || defined(sun))
if (CRYPTOPP_GCC_VERSION >= 30000) || (CRYPTOPP_LLVM_CLANG_VERSION >= 20900) || (_INTEL_COMPILER >= 800)
#endif // CRYPTOPP_INIT_PRIORITY, NO_OS_DEPENDENCE, Apple, Sun
// ***************** determine availability of OS features ********************
#ifndef NO_OS_DEPENDENCE
#if defined(_WIN32) || defined(_WIN64) || defined(CYGWIN) #define CRYPTOPP_WIN32_AVAILABLE #endif
#if defined(unix) || defined(MACH) || defined(NetBSD) || defined(__sun) #define CRYPTOPP_UNIX_AVAILABLE #endif
#if defined(FreeBSD) || defined(NetBSD) || defined(OpenBSD) || defined(DragonFly) #define CRYPTOPP_BSD_AVAILABLE #endif
#if defined(CRYPTOPP_WIN32_AVAILABLE) || defined(CRYPTOPP_UNIX_AVAILABLE)
#endif
#ifdef CRYPTOPP_WIN32_AVAILABLE
#endif
#if defined(CRYPTOPP_UNIX_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING)
#endif
// Cygwin/Newlib requires _XOPEN_SOURCE=600 #if defined(CRYPTOPP_UNIX_AVAILABLE)
#endif
#ifdef CRYPTOPP_WIN32_AVAILABLE
#endif
#endif // NO_OS_DEPENDENCE
// ***************** DLL related ********************
#if defined(CRYPTOPP_WIN32_AVAILABLE) && !defined(CRYPTOPP_DOXYGEN_PROCESSING)
#ifdef CRYPTOPP_EXPORTS #define CRYPTOPP_IS_DLL #define CRYPTOPP_DLL __declspec(dllexport) #elif defined(CRYPTOPP_IMPORTS) #define CRYPTOPP_IS_DLL #define CRYPTOPP_DLL __declspec(dllimport) #else #define CRYPTOPP_DLL #endif
// C++ makes const internal linkage #define CRYPTOPP_TABLE extern #define CRYPTOPP_API __cdecl
#else // not CRYPTOPP_WIN32_AVAILABLE
// C++ makes const internal linkage #define CRYPTOPP_TABLE extern #define CRYPTOPP_DLL #define CRYPTOPP_API
#endif // CRYPTOPP_WIN32_AVAILABLE
#if defined(MWERKS) #define CRYPTOPP_EXTERN_DLL_TEMPLATE_CLASS extern class CRYPTOPP_DLL #elif defined(BORLANDC) || defined(__SUNPRO_CC) #define CRYPTOPP_EXTERN_DLL_TEMPLATE_CLASS template class CRYPTOPP_DLL #else #define CRYPTOPP_EXTERN_DLL_TEMPLATE_CLASS extern template class CRYPTOPP_DLL #endif
#if defined(CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES) && !defined(CRYPTOPP_IMPORTS) #define CRYPTOPP_DLL_TEMPLATE_CLASS template class CRYPTOPP_DLL #else #define CRYPTOPP_DLL_TEMPLATE_CLASS CRYPTOPP_EXTERN_DLL_TEMPLATE_CLASS #endif
#if defined(MWERKS) #define CRYPTOPP_EXTERN_STATIC_TEMPLATE_CLASS extern class #elif defined(BORLANDC) || defined(__SUNPRO_CC) #define CRYPTOPP_EXTERN_STATIC_TEMPLATE_CLASS template class #else #define CRYPTOPP_EXTERN_STATIC_TEMPLATE_CLASS extern template class #endif
#if defined(CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES) && !defined(CRYPTOPP_EXPORTS) #define CRYPTOPP_STATIC_TEMPLATE_CLASS template class #else #define CRYPTOPP_STATIC_TEMPLATE_CLASS CRYPTOPP_EXTERN_STATIC_TEMPLATE_CLASS #endif
// ************** Unused variable ***************
// Portable way to suppress warnings. // Moved from misc.h due to circular depenedencies. #define CRYPTOPP_UNUSED(x) ((void)(x))
// ************** Deprecated ***************
#if (CRYPTOPP_GCC_VERSION >= 40500) || (CRYPTOPP_LLVM_CLANG_VERSION >= 20800) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40200)
#elif (CRYPTOPP_GCC_VERSION)
#else
#endif
// ***************** C++11 related ********************
// Visual Studio began at VS2010, http://msdn.microsoft.com/en-us/library/hh567368%28v=vs.110%29.aspx // and https://docs.microsoft.com/en-us/cpp/visual-cpp-language-conformance . // Intel, http://software.intel.com/en-us/articles/c0x-features-supported-by-intel-c-compiler // GCC, http://gcc.gnu.org/projects/cxx0x.html // Clang, http://clang.llvm.org/cxx_status.html
// Compatibility with non-clang compilers. #ifndef __has_feature
#endif
#if !defined(CRYPTOPP_NO_CXX11)
#endif
// Hack ahead. Apple's standard library does not have C++'s unique_ptr in C++11. We can't // test for unique_ptr directly because some of the non-Apple Clangs on OS X fail the same // way. However, modern standard libraries have <forward_list>, so we test for it instead. // Thanks to Jonathan Wakely for devising the clever test for modern/ancient versions. // TODO: test under Xcode 3, where g++ is really g++. #if defined(APPLE) && defined(clang)
#endif
// C++11 or C++14 is available #if defined(CRYPTOPP_CXX11)
// atomics: MS at VS2012 (17.00); GCC at 4.4; Clang at 3.1/3.2; Intel 13.0; SunCC 5.14.
#if (CRYPTOPP_MSC_VERSION >= 1700) || __has_feature(cxx_atomic) ||
(__INTEL_COMPILER >= 1300) || (CRYPTOPP_GCC_VERSION >= 40400) || (__SUNPRO_CC >= 0x5140)
#endif // atomics
// synchronization: MS at VS2012 (17.00); GCC at 4.4; Clang at 3.3; Xcode 5.0; Intel 12.0; SunCC 5.13.
// TODO: verify Clang and Intel versions; find __has_feature(x) extension for Clang
#if (CRYPTOPP_MSC_VERSION >= 1700) || (CRYPTOPP_LLVM_CLANG_VERSION >= 30300) ||
(CRYPTOPP_APPLE_CLANG_VERSION >= 50000) || (__INTEL_COMPILER >= 1200) ||
(CRYPTOPP_GCC_VERSION >= 40400) || (__SUNPRO_CC >= 0x5130)
// Hack ahead. New GCC compilers like GCC 6 on AIX 7.0 or earlier as well as original MinGW
// don't have the synchronization gear. However, Wakely's test used for Apple does not work
// on the GCC/AIX combination. Another twist is we need other stuff from C++11,
// like no-except destructors. Dumping preprocessors shows the following may
// apply: http://stackoverflow.com/q/14191566/608639.
#endif // synchronization
// Dynamic Initialization and Destruction with Concurrency ("Magic Statics")
// MS at VS2015 with Vista (19.00); GCC at 4.3; LLVM Clang at 2.9; Apple Clang at 4.0; Intel 11.1; SunCC 5.13.
// Microsoft's implementation only works for Vista and above, so its further
// limited. http://connect.microsoft.com/VisualStudio/feedback/details/1789709
#if (CRYPTOPP_MSC_VERSION >= 1900) && ((WINVER >= 0x0600) || (_WIN32_WINNT >= 0x0600)) ||
(CRYPTOPP_LLVM_CLANG_VERSION >= 20900) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40000) ||
(__INTEL_COMPILER >= 1110) || (CRYPTOPP_GCC_VERSION >= 40300) || (__SUNPRO_CC >= 0x5130)
#endif // Dynamic Initialization compilers
// alignof/alignas: MS at VS2015 (19.00); GCC at 4.8; Clang at 3.0; Intel 15.0; SunCC 5.13.
#if (CRYPTOPP_MSC_VERSION >= 1900) || __has_feature(cxx_alignas) ||
(__INTEL_COMPILER >= 1500) || (CRYPTOPP_GCC_VERSION >= 40800) || (__SUNPRO_CC >= 0x5130)
#endif // alignas
// alignof: MS at VS2015 (19.00); GCC at 4.5; Clang at 2.9; Intel 15.0; SunCC 5.13.
#if (CRYPTOPP_MSC_VERSION >= 1900) || __has_feature(cxx_alignof) ||
(__INTEL_COMPILER >= 1500) || (CRYPTOPP_GCC_VERSION >= 40500) || (__SUNPRO_CC >= 0x5130)
#endif // alignof
// lambdas: MS at VS2012 (17.00); GCC at 4.9; Clang at 3.3; Intel 12.0; SunCC 5.14.
#if (CRYPTOPP_MSC_VERSION >= 1700) || __has_feature(cxx_lambdas) ||
(__INTEL_COMPILER >= 1200) || (CRYPTOPP_GCC_VERSION >= 40900) || (__SUNPRO_CC >= 0x5140)
#endif // lambdas
// noexcept: MS at VS2015 (19.00); GCC at 4.6; Clang at 3.0; Intel 14.0; SunCC 5.13.
#if (CRYPTOPP_MSC_VERSION >= 1900) || __has_feature(cxx_noexcept) ||
(__INTEL_COMPILER >= 1400) || (CRYPTOPP_GCC_VERSION >= 40600) || (__SUNPRO_CC >= 0x5130)
#endif // noexcept compilers
// variadic templates: MS at VS2013 (18.00); GCC at 4.3; Clang at 2.9; Intel 12.1; SunCC 5.13.
#if (CRYPTOPP_MSC_VERSION >= 1800) || __has_feature(cxx_variadic_templates) ||
(__INTEL_COMPILER >= 1210) || (CRYPTOPP_GCC_VERSION >= 40300) || (__SUNPRO_CC >= 0x5130)
#endif // variadic templates
// constexpr: MS at VS2015 (19.00); GCC at 4.6; Clang at 3.1; Intel 16.0; SunCC 5.13.
// Intel has mis-supported the feature since at least ICPC 13.00
#if (CRYPTOPP_MSC_VERSION >= 1900) || __has_feature(cxx_constexpr) ||
(__INTEL_COMPILER >= 1600) || (CRYPTOPP_GCC_VERSION >= 40600) || (__SUNPRO_CC >= 0x5130)
#endif // constexpr compilers
// strong typed enums: MS at VS2012 (17.00); GCC at 4.4; Clang at 3.3; Intel 14.0; SunCC 5.12.
// Mircorosft and Intel had partial support earlier, but we require full support.
#if (CRYPTOPP_MSC_VERSION >= 1700) || __has_feature(cxx_strong_enums) ||
(__INTEL_COMPILER >= 1400) || (CRYPTOPP_GCC_VERSION >= 40400) || (__SUNPRO_CC >= 0x5120)
#endif // constexpr compilers
// nullptr_t: MS at VS2010 (16.00); GCC at 4.6; Clang at 3.3; Intel 10.0; SunCC 5.13.
#if (CRYPTOPP_MSC_VERSION >= 1600) || __has_feature(cxx_nullptr) ||
(__INTEL_COMPILER >= 1000) || (CRYPTOPP_GCC_VERSION >= 40600) ||
(__SUNPRO_CC >= 0x5130) || defined(__IBMCPP_NULLPTR)
#endif // nullptr_t compilers
#endif // CRYPTOPP_CXX11
// ***************** C++17 related ********************
// C++17 macro version, https://stackoverflow.com/q/38456127/608639 #if defined(CRYPTOPP_CXX11) && !defined(CRYPTOPP_NO_CXX17)
#endif
// C++17 is available #if defined(CRYPTOPP_CXX17)
// C++17 uncaught_exceptions: MS at VS2015 (19.00); GCC at 6.0; Clang at 3.5; Intel 18.0. // Clang and __EXCEPTIONS see http://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html #if defined(clang)
#elif (CRYPTOPP_MSC_VERSION >= 1900) || (__INTEL_COMPILER >= 1800) || (CRYPTOPP_GCC_VERSION >= 60000) || (__cpp_lib_uncaught_exceptions)
#endif // uncaught_exceptions compilers
#endif // CRYPTOPP_CXX17
// ***************** C++ fixups ********************
#if defined(CRYPTOPP_CXX11_NOEXCEPT)
#else
#endif // CRYPTOPP_CXX11_NOEXCEPT
// http://stackoverflow.com/a/13867690/608639 #if defined(CRYPTOPP_CXX11_CONSTEXPR)
#else
#endif // CRYPTOPP_CXX11_CONSTEXPR
// Hack... CRYPTOPP_ALIGN_DATA is defined earlier, before C++11 alignas availability is determined #if defined(CRYPTOPP_CXX11_ALIGNAS)
#endif // CRYPTOPP_CXX11_ALIGNAS
// Hack... CRYPTOPP_CONSTANT is defined earlier, before C++11 constexpr availability is determined // http://stackoverflow.com/q/35213098/608639 // #if defined(CRYPTOPP_CXX11_CONSTEXPR) // # undef CRYPTOPP_CONSTANT // # define CRYPTOPP_CONSTANT(x) constexpr static int x; // #endif
// Hack... CRYPTOPP_CONSTANT is defined earlier, before C++11 constexpr availability is determined // http://stackoverflow.com/q/35213098/608639 #if defined(CRYPTOPP_CXX11_ENUM)
#elif defined(CRYPTOPP_CXX11_CONSTEXPR)
#endif
// Hack... C++11 nullptr_t type safety and analysis #if defined(CRYPTOPP_CXX11_NULLPTR) && !defined(NULLPTR)
#elif !defined(NULLPTR)
#endif // CRYPTOPP_CXX11_NULLPTR
// OK to comment the following out, but please report it so we can fix it. // C++17 value taken from http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4567.pdf. #if (defined(__cplusplus) && (__cplusplus >= 199711L) && (__cplusplus < 201402L)) && !defined(CRYPTOPP_UNCAUGHT_EXCEPTION_AVAILABLE)
#endif
#endif // CRYPTOPP_CONFIG_H
//cryptlib.h================================================================================================
// cryptlib.h - originally written and placed in the public domain by Wei Dai
/// \file cryptlib.h /// \brief Abstract base classes that provide a uniform interface to this library.
/*! \mainpage Crypto++ Library 8.2 API Reference
- Abstract Base Classes
- cryptlib.h
- Authenticated Encryption Modes
- CCM, EAX, \ref GCM "GCM (2K tables)", \ref GCM "GCM (64K tables)"
- Block Ciphers
- \ref Rijndael "AES", ARIA, Weak::ARC4, Blowfish, BTEA, \ref CHAM128 "CHAM (64/128)", Camellia, \ref CAST128 "CAST (128/256)", DES, \ref DES_EDE2 "2-key Triple-DES", \ref DES_EDE3 "3-key Triple-DES", \ref DES_XEX3 "DESX", GOST, HIGHT, IDEA, LEA, \ref LR "Luby-Rackoff", \ref Kalyna128 "Kalyna (128/256/512)", MARS, RC2, RC5, RC6, \ref SAFER_K "SAFER-K", \ref SAFER_SK "SAFER-SK", SEED, Serpent, \ref SHACAL2 "SHACAL-2", SHARK, \ref SIMECK64 "SIMECK (32/64)" SKIPJACK, SM4, Square, TEA, \ref ThreeWay "3-Way", \ref Threefish256 "Threefish (256/512/1024)", Twofish, XTEA
- Stream Ciphers
- \ref ChaCha "ChaCha (8/12/20)", \ref HC128 "HC-128/256", \ref Panama "Panama-LE", \ref Panama "Panama-BE", Rabbit, Salsa20, \ref SEAL "SEAL-LE", \ref SEAL "SEAL-BE", WAKE, XSalsa20
- Hash Functions
- BLAKE2s, BLAKE2b, \ref Keccak "Keccak (F1600)", SHA1, SHA224, SHA256, SHA384, SHA512, \ref SHA3 "SHA-3", SM3, Tiger, RIPEMD160, RIPEMD320, RIPEMD128, RIPEMD256, SipHash, Whirlpool, Weak::MD2, Weak::MD4, Weak::MD5
- Non-Cryptographic Checksums
- CRC32, CRC32C, Adler32
- Message Authentication Codes
- BLAKE2b, BLAKE2s, CBC_MAC, CMAC, DMAC, \ref GCM "GCM (GMAC)", HMAC, Poly1305, TTMAC, VMAC
- Random Number Generators
- NullRNG, LC_RNG, RandomPool, BlockingRng, NonblockingRng, AutoSeededRandomPool, AutoSeededX917RNG, NIST Hash_DRBG and HMAC_DRBG, \ref MersenneTwister "MersenneTwister (MT19937 and MT19937-AR)", DARN, RDRAND, RDSEED
- Key Derivation and Password-based Cryptography
- HKDF, \ref PKCS12_PBKDF "PBKDF (PKCS #12)", \ref PKCS5_PBKDF1 "PBKDF-1 (PKCS #5)", \ref PKCS5_PBKDF2_HMAC "PBKDF-2/HMAC (PKCS #5)"
- Public Key Cryptosystems
- DLIES, ECIES, LUCES, RSAES, RabinES, LUC_IES
- Public Key Signature Schemes
- DSA, DSA2, \ref ed25519 "Ed25519", GDSA, ECDSA, NR, ECNR, LUCSS, RSASS, RSASS_ISO, RabinSS, RWSS, ESIGN
- Key Agreement
- DH, DH2, \ref x25519 "X25519", \ref MQV_Domain "MQV", \ref HMQV_Domain "HMQV", \ref FHMQV_Domain "FHMQV", ECDH, x25519, ECMQV, ECHMQV, ECFHMQV, XTR_DH
- Algebraic Structures
- Integer, PolynomialMod2, PolynomialOver, RingOfPolynomialsOver, ModularArithmetic, MontgomeryRepresentation, GFP2_ONB, GF2NP, GF256, GF2_32, EC2N, ECP
- Secret Sharing and Information Dispersal
- SecretSharing, SecretRecovery, InformationDispersal, InformationRecovery
- Compression
- Deflator, Inflator, Gzip, Gunzip, ZlibCompressor, ZlibDecompressor
- Input Source Classes
- StringSource, ArraySource, VectorSource, FileSource, RandomNumberSource
- Output Sink Classes
- StringSinkTemplate, StringSink, VectorSink, ArraySink, FileSink, RandomNumberSink
- Filter Wrappers
- StreamTransformationFilter, AuthenticatedEncryptionFilter, AuthenticatedDecryptionFilter, HashFilter, HashVerificationFilter, SignerFilter, SignatureVerificationFilter
- Binary to Text Encoders and Decoders
- HexEncoder, HexDecoder, Base64Encoder, Base64Decoder, Base64URLEncoder, Base64URLDecoder, Base32Encoder, Base32Decoder
- Wrappers for OS features
- Timer, ThreadUserTimer
This reference manual is a work in progress. Some classes lack detailed descriptions.
Click here to download a zip archive containing this manual.
Thanks to Ryan Phillips for providing the Doxygen configuration file and getting us started on the manual. */
#ifndef CRYPTOPP_CRYPTLIB_H #define CRYPTOPP_CRYPTLIB_H
#include "config.h" #include "stdcpp.h" #include "trap.h"
#if CRYPTOPP_MSC_VERSION
#endif
NAMESPACE_BEGIN(CryptoPP)
// forward declarations class Integer; class RandomNumberGenerator; class BufferedTransformation;
/// \brief Specifies a direction for a cipher to operate /// \sa BlockTransformation::IsForwardTransformation(), BlockTransformation::IsPermutation(), BlockTransformation::GetCipherDirection() enum CipherDir { /// \brief the cipher is performing encryption ENCRYPTION, /// \brief the cipher is performing decryption DECRYPTION};
/// \brief Represents infinite time const unsigned long INFINITE_TIME = ULONG_MAX;
// VC60 workaround: using enums as template parameters causes problems /// \brief Converts an enumeration to a type suitable for use as a template parameter template <typename ENUM_TYPE, int VALUE> struct EnumToType { static ENUM_TYPE ToEnum() {return static_cast<ENUM_TYPE>(VALUE);} };
/// \brief Provides the byte ordering /// \details Big-endian and little-endian modes are supported. Bi-endian and PDP-endian modes /// are not supported. enum ByteOrder { /// \brief byte order is little-endian LITTLE_ENDIAN_ORDER = 0, /// \brief byte order is big-endian BIG_ENDIAN_ORDER = 1};
/// \brief Provides a constant for LittleEndian typedef EnumToType<ByteOrder, LITTLE_ENDIAN_ORDER> LittleEndian; /// \brief Provides a constant for BigEndian typedef EnumToType<ByteOrder, BIG_ENDIAN_ORDER> BigEndian;
/// \brief Base class for all exceptions thrown by the library /// \details All library exceptions directly or indirectly inherit from the Exception class. /// The Exception class itself inherits from std::exception. The library does not use /// std::runtime_error derived classes. class CRYPTOPP_DLL Exception : public std::exception { public: /// \enum ErrorType /// \brief Error types or categories enum ErrorType { /// \brief A method was called which was not implemented NOT_IMPLEMENTED, /// \brief An invalid argument was detected INVALID_ARGUMENT, /// \brief BufferedTransformation received a Flush(true) signal but can't flush buffers CANNOT_FLUSH, /// \brief Data integerity check, such as CRC or MAC, failed DATA_INTEGRITY_CHECK_FAILED, /// \brief Input data was received that did not conform to expected format INVALID_DATA_FORMAT, /// \brief Error reading from input device or writing to output device IO_ERROR, /// \brief Some other error occurred not belonging to other categories OTHER_ERROR };
virtual ~Exception() throw() {}
/// \brief Construct a new Exception
explicit Exception(ErrorType errorType, const std::string &s) : m_errorType(errorType), m_what(s) {}
/// \brief Retrieves a C-string describing the exception
const char *what() const throw() {return (m_what.c_str());}
/// \brief Retrieves a string describing the exception
const std::string &GetWhat() const {return m_what;}
/// \brief Sets the error string for the exception
void SetWhat(const std::string &s) {m_what = s;}
/// \brief Retrieves the error type for the exception
ErrorType GetErrorType() const {return m_errorType;}
/// \brief Sets the error type for the exceptions
void SetErrorType(ErrorType errorType) {m_errorType = errorType;}
private: ErrorType m_errorType; std::string m_what; };
/// \brief An invalid argument was detected class CRYPTOPP_DLL InvalidArgument : public Exception { public: explicit InvalidArgument(const std::string &s) : Exception(INVALID_ARGUMENT, s) {} };
/// \brief Input data was received that did not conform to expected format class CRYPTOPP_DLL InvalidDataFormat : public Exception { public: explicit InvalidDataFormat(const std::string &s) : Exception(INVALID_DATA_FORMAT, s) {} };
/// \brief A decryption filter encountered invalid ciphertext class CRYPTOPP_DLL InvalidCiphertext : public InvalidDataFormat { public: explicit InvalidCiphertext(const std::string &s) : InvalidDataFormat(s) {} };
/// \brief A method was called which was not implemented class CRYPTOPP_DLL NotImplemented : public Exception { public: explicit NotImplemented(const std::string &s) : Exception(NOT_IMPLEMENTED, s) {} };
/// \brief Flush(true) was called but it can't completely flush its buffers class CRYPTOPP_DLL CannotFlush : public Exception { public: explicit CannotFlush(const std::string &s) : Exception(CANNOT_FLUSH, s) {} };
/// \brief The operating system reported an error class CRYPTOPP_DLL OS_Error : public Exception { public: virtual ~OS_Error() throw() {} OS_Error(ErrorType errorType, const std::string &s, const std::string& operation, int errorCode) : Exception(errorType, s), m_operation(operation), m_errorCode(errorCode) {}
/// \brief Retrieve the operating system API that reported the error
const std::string & GetOperation() const {return m_operation;}
/// \brief Retrieve the error code returned by the operating system
int GetErrorCode() const {return m_errorCode;}
protected: std::string m_operation; int m_errorCode; };
/// \brief Returns a decoding results struct CRYPTOPP_DLL DecodingResult { /// \brief Constructs a DecodingResult /// \details isValidCoding is initialized to false and messageLength is initialized to 0. explicit DecodingResult() : isValidCoding(false), messageLength(0) {} /// \brief Constructs a DecodingResult /// \param len the message length /// \details isValidCoding is initialized to true. explicit DecodingResult(size_t len) : isValidCoding(true), messageLength(len) {}
/// \brief Compare two DecodingResult
/// \param rhs the other DecodingResult
/// \return true if both isValidCoding and messageLength are equal, false otherwise
bool operator==(const DecodingResult &rhs) const {return isValidCoding == rhs.isValidCoding && messageLength == rhs.messageLength;}
/// \brief Compare two DecodingResult
/// \param rhs the other DecodingResult
/// \return true if either isValidCoding or messageLength is \a not equal, false otherwise
/// \details Returns <tt>!operator==(rhs)</tt>.
bool operator!=(const DecodingResult &rhs) const {return !operator==(rhs);}
/// \brief Flag to indicate the decoding is valid
bool isValidCoding;
/// \brief Recovered message length if isValidCoding is true, undefined otherwise
size_t messageLength;
};
/// \brief Interface for retrieving values given their names /// \details This class is used to safely pass a variable number of arbitrarily typed arguments to functions /// and to read values from keys and crypto parameters. /// \details To obtain an object that implements NameValuePairs for the purpose of parameter /// passing, use the MakeParameters() function. /// \details To get a value from NameValuePairs, you need to know the name and the type of the value. /// Call GetValueNames() on a NameValuePairs object to obtain a list of value names that it supports. /// then look at the Name namespace documentation to see what the type of each value is, or /// alternatively, call GetIntValue() with the value name, and if the type is not int, a /// ValueTypeMismatch exception will be thrown and you can get the actual type from the exception object. /// \sa NullNameValuePairs, g_nullNameValuePairs, /// NameValuePairs on the Crypto++ wiki class NameValuePairs { public: virtual ~NameValuePairs() {}
/// \brief Thrown when an unexpected type is encountered
/// \details Exception thrown when trying to retrieve a value using a different type than expected
class CRYPTOPP_DLL ValueTypeMismatch : public InvalidArgument
{
public:
/// \brief Construct a ValueTypeMismatch
/// \param name the name of the value
/// \param stored the \a actual type of the value stored
/// \param retrieving the \a presumed type of the value retrieved
ValueTypeMismatch(const std::string &name, const std::type_info &stored, const std::type_info &retrieving)
: InvalidArgument("NameValuePairs: type mismatch for '" + name + "', stored '" + stored.name() + "', trying to retrieve '" + retrieving.name() + "'")
, m_stored(stored), m_retrieving(retrieving) {}
/// \brief Provides the stored type
/// \return the C++ mangled name of the type
const std::type_info & GetStoredTypeInfo() const {return m_stored;}
/// \brief Provides the retrieveing type
/// \return the C++ mangled name of the type
const std::type_info & GetRetrievingTypeInfo() const {return m_retrieving;}
private:
const std::type_info &m_stored;
const std::type_info &m_retrieving;
};
/// \brief Get a copy of this object or subobject
/// \tparam T class or type
/// \param object reference to a variable that receives the value
template <class T>
bool GetThisObject(T &object) const
{
return GetValue((std::string("ThisObject:")+typeid(T).name()).c_str(), object);
}
/// \brief Get a pointer to this object
/// \tparam T class or type
/// \param ptr reference to a pointer to a variable that receives the value
template <class T>
bool GetThisPointer(T *&ptr) const
{
return GetValue((std::string("ThisPointer:")+typeid(T).name()).c_str(), ptr);
}
/// \brief Get a named value
/// \tparam T class or type
/// \param name the name of the object or value to retrieve
/// \param value reference to a variable that receives the value
/// \returns true if the value was retrieved, false otherwise
/// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(),
/// GetRequiredParameter() and GetRequiredIntParameter()
template <class T>
bool GetValue(const char *name, T &value) const
{
return GetVoidValue(name, typeid(T), &value);
}
/// \brief Get a named value
/// \tparam T class or type
/// \param name the name of the object or value to retrieve
/// \param defaultValue the default value of the class or type if it does not exist
/// \return the object or value
/// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(),
/// GetRequiredParameter() and GetRequiredIntParameter()
template <class T>
T GetValueWithDefault(const char *name, T defaultValue) const
{
T value;
bool result = GetValue(name, value);
// No assert... this recovers from failure
if (result) {return value;}
return defaultValue;
}
/// \brief Get a list of value names that can be retrieved
/// \return a list of names available to retrieve
/// \details the items in the list are delimited with a colon.
CRYPTOPP_DLL std::string GetValueNames() const
{std::string result; GetValue("ValueNames", result); return result;}
/// \brief Get a named value with type int
/// \param name the name of the value to retrieve
/// \param value the value retrieved upon success
/// \return true if an int value was retrieved, false otherwise
/// \details GetIntValue() is used to ensure we don't accidentally try to get an
/// unsigned int or some other type when we mean int (which is the most common case)
/// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(),
/// GetRequiredParameter() and GetRequiredIntParameter()
CRYPTOPP_DLL bool GetIntValue(const char *name, int &value) const
{return GetValue(name, value);}
/// \brief Get a named value with type int, with default
/// \param name the name of the value to retrieve
/// \param defaultValue the default value if the name does not exist
/// \return the value retrieved on success or the default value
/// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(),
/// GetRequiredParameter() and GetRequiredIntParameter()
CRYPTOPP_DLL int GetIntValueWithDefault(const char *name, int defaultValue) const
{return GetValueWithDefault(name, defaultValue);}
/// \brief Get a named value with type word64
/// \param name the name of the value to retrieve
/// \param value the value retrieved upon success
/// \return true if an word64 value was retrieved, false otherwise
/// \sa GetValue(), GetValueWithDefault(), GetWord64ValueWithDefault(), GetIntValue(),
/// GetIntValueWithDefault(), GetRequiredParameter() and GetRequiredIntParameter()
CRYPTOPP_DLL bool GetWord64Value(const char *name, word64 &value) const
{return GetValue(name, value);}
/// \brief Get a named value with type word64, with default
/// \param name the name of the value to retrieve
/// \param defaultValue the default value if the name does not exist
/// \return the value retrieved on success or the default value
/// \sa GetValue(), GetValueWithDefault(), GetWord64Value(), GetIntValue(),
/// GetIntValueWithDefault(), GetRequiredParameter() and GetRequiredWord64Parameter()
CRYPTOPP_DLL word64 GetWord64ValueWithDefault(const char *name, word64 defaultValue) const
{return GetValueWithDefault(name, defaultValue);}
/// \brief Ensures an expected name and type is present
/// \param name the name of the value
/// \param stored the type that was stored for the name
/// \param retrieving the type that is being retrieved for the name
/// \throws ValueTypeMismatch
/// \details ThrowIfTypeMismatch() effectively performs a type safety check.
/// stored and retrieving are C++ mangled names for the type.
/// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(),
/// GetRequiredParameter() and GetRequiredIntParameter()
CRYPTOPP_DLL static void CRYPTOPP_API ThrowIfTypeMismatch(const char *name, const std::type_info &stored, const std::type_info &retrieving)
{if (stored != retrieving) throw ValueTypeMismatch(name, stored, retrieving);}
/// \brief Retrieves a required name/value pair
/// \tparam T class or type
/// \param className the name of the class
/// \param name the name of the value
/// \param value reference to a variable to receive the value
/// \throws InvalidArgument
/// \details GetRequiredParameter() throws InvalidArgument if the name
/// is not present or not of the expected type T.
/// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(),
/// GetRequiredParameter() and GetRequiredIntParameter()
template <class T>
void GetRequiredParameter(const char *className, const char *name, T &value) const
{
if (!GetValue(name, value))
throw InvalidArgument(std::string(className) + ": missing required parameter '" + name + "'");
}
/// \brief Retrieves a required name/value pair
/// \param className the name of the class
/// \param name the name of the value
/// \param value reference to a variable to receive the value
/// \throws InvalidArgument
/// \details GetRequiredParameter() throws InvalidArgument if the name
/// is not present or not of the expected type T.
/// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(),
/// GetRequiredParameter() and GetRequiredIntParameter()
CRYPTOPP_DLL void GetRequiredIntParameter(const char *className, const char *name, int &value) const
{
if (!GetIntValue(name, value))
throw InvalidArgument(std::string(className) + ": missing required parameter '" + name + "'");
}
/// \brief Get a named value
/// \param name the name of the object or value to retrieve
/// \param valueType reference to a variable that receives the value
/// \param pValue void pointer to a variable that receives the value
/// \returns true if the value was retrieved, false otherwise
/// \details GetVoidValue() retrieves the value of name if it exists.
/// \note GetVoidValue() is an internal function and should be implemented
/// by derived classes. Users should use one of the other functions instead.
/// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(),
/// GetRequiredParameter() and GetRequiredIntParameter()
CRYPTOPP_DLL virtual bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const =0;
};
// Doxygen cannot handle initialization #if CRYPTOPP_DOXYGEN_PROCESSING /// \brief Default channel for BufferedTransformation /// \details DEFAULT_CHANNEL is equal to an empty string /// \details The definition for DEFAULT_CHANNEL is in cryptlib.cpp. /// It can be subject to Static /// Initialization Order Fiasco. If you experience a crash in /// DEFAULT_CHANNEL where the string object is NULL, then you probably have /// a global object using DEFAULT_CHANNEL before it has been constructed. const std::string DEFAULT_CHANNEL;
/// \brief Channel for additional authenticated data /// \details AAD_CHANNEL is equal to "AAD" /// \details The definition for AAD_CHANNEL is in cryptlib.cpp. /// It can be subject to Static /// Initialization Order Fiasco. If you experience a crash in /// AAD_CHANNEL where the string object is NULL, then you probably have a /// global object using AAD_CHANNEL before it has been constructed. const std::string AAD_CHANNEL;
/// \brief An empty set of name-value pairs /// \details The definition for g_nullNameValuePairs is in cryptlib.cpp. /// It can be subject to Static /// Initialization Order Fiasco. If you experience a crash in /// g_nullNameValuePairs where the string object is NULL, then you probably /// have a global object using g_nullNameValuePairs before it has been /// constructed. const NameValuePairs& g_nullNameValuePairs;
#else extern CRYPTOPP_DLL const std::string DEFAULT_CHANNEL; extern CRYPTOPP_DLL const std::string AAD_CHANNEL; extern CRYPTOPP_DLL const NameValuePairs& g_nullNameValuePairs; #endif
// Document additional name spaces which show up elsewhere in the sources. #if CRYPTOPP_DOXYGEN_PROCESSING /// \brief Namespace containing value name definitions. /// \details Name is part of the CryptoPP namespace. /// \details The semantics of value names, types are: ///
/// ThisObject:ClassName (ClassName, copy of this object or a subobject) /// ThisPointer:ClassName (const ClassName *, pointer to this object or a subobject) ///DOCUMENTED_NAMESPACE_BEGIN(Name) // more names defined in argnames.h DOCUMENTED_NAMESPACE_END
/// \brief Namespace containing weak and wounded algorithms. /// \details Weak is part of the CryptoPP namespace. Schemes and algorithms are moved into Weak /// when their security level is reduced to an unacceptable level by contemporary standards. /// \details To use an algorithm in the Weak namespace, you must \c #define /// CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 before including a header for a weak or wounded /// algorithm. For example: ///
/// \c #define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 /// \c #include <md5.h> /// ... /// CryptoPP::Weak::MD5 md5; ///DOCUMENTED_NAMESPACE_BEGIN(Weak) // weak and wounded algorithms DOCUMENTED_NAMESPACE_END #endif
/// \brief Namespace containing NaCl library functions /// \details TweetNaCl is a compact and portable reimplementation of the NaCl library. DOCUMENTED_NAMESPACE_BEGIN(NaCl) // crypto_box, crypto_box_open, crypto_sign, and crypto_sign_open (and friends) DOCUMENTED_NAMESPACE_END
/// \brief Namespace containing testing and benchmark classes. /// \details Source files for classes in the Test namespaces include /// test.cpp, validat#.cpp and bench#.cpp. DOCUMENTED_NAMESPACE_BEGIN(Test) // testing and benchmark classes DOCUMENTED_NAMESPACE_END
// ********************************************************
/// \brief Interface for cloning objects /// \note this is \a not implemented by most classes /// \sa ClonableImpl, NotCopyable class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Clonable { public: virtual ~Clonable() {}
/// \brief Copies this object
/// \return a copy of this object
/// \throws NotImplemented
/// \note this is \a not implemented by most classes
/// \sa NotCopyable
virtual Clonable* Clone() const {throw NotImplemented("Clone() is not implemented yet.");} // TODO: make this =0
};
/// \brief Interface for all crypto algorithms class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Algorithm : public Clonable { public: virtual ~Algorithm() {}
/// \brief Interface for all crypto algorithms
/// \param checkSelfTestStatus determines whether the object can proceed if the self
/// tests have not been run or failed.
/// \details When FIPS 140-2 compliance is enabled and checkSelfTestStatus == true,
/// this constructor throws SelfTestFailure if the self test hasn't been run or fails.
/// \details FIPS 140-2 compliance is disabled by default. It is only used by certain
/// versions of the library when the library is built as a DLL on Windows. Also see
/// CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 in config.h.
Algorithm(bool checkSelfTestStatus = true);
/// \brief Provides the name of this algorithm
/// \return the standard algorithm name
/// \details The standard algorithm name can be a name like <tt>AES</tt> or <tt>AES/GCM</tt>.
/// Some algorithms do not have standard names yet. For example, there is no standard
/// algorithm name for Shoup's ECIES.
/// \note AlgorithmName is not universally implemented yet.
virtual std::string AlgorithmName() const {return "unknown";}
/// \brief Retrieve the provider of this algorithm
/// \return the algorithm provider
/// \details The algorithm provider can be a name like "C++", "SSE", "NEON", "AESNI",
/// "ARMv8" and "Power8". C++ is standard C++ code. Other labels, like SSE,
/// usually indicate a specialized implementation using instructions from a higher
/// instruction set architecture (ISA). Future labels may include external hardware
/// like a hardware security module (HSM).
/// \details Generally speaking Wei Dai's original IA-32 ASM code falls under "SSE2".
/// Labels like "SSSE3" and "SSE4.1" follow after Wei's code and use intrinsics
/// instead of ASM.
/// \details Algorithms which combine different instructions or ISAs provide the
/// dominant one. For example on x86 <tt>AES/GCM</tt> returns "AESNI" rather than
/// "CLMUL" or "AES+SSE4.1" or "AES+CLMUL" or "AES+SSE4.1+CLMUL".
/// \note Provider is not universally implemented yet.
/// \since Crypto++ 8.0
virtual std::string AlgorithmProvider() const {return "C++";}
};
/// \brief Interface for algorithms that take byte strings as keys /// \sa FixedKeyLength(), VariableKeyLength(), SameKeyLengthAs(), SimpleKeyingInterfaceImpl() class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE SimpleKeyingInterface { public: virtual ~SimpleKeyingInterface() {}
/// \brief Returns smallest valid key length
/// \returns the minimum key length, in bytes
virtual size_t MinKeyLength() const =0;
/// \brief Returns largest valid key length
/// \returns the maximum key length, in bytes
virtual size_t MaxKeyLength() const =0;
/// \brief Returns default key length
/// \returns the default key length, in bytes
virtual size_t DefaultKeyLength() const =0;
/// \brief Returns a valid key length for the algorithm
/// \param keylength the size of the key, in bytes
/// \returns the valid key length, in bytes
/// \details keylength is provided in bytes, not bits. If keylength is less than MIN_KEYLENGTH,
/// then the function returns MIN_KEYLENGTH. If keylength is greater than MAX_KEYLENGTH,
/// then the function returns MAX_KEYLENGTH. if If keylength is a multiple of KEYLENGTH_MULTIPLE,
/// then keylength is returned. Otherwise, the function returns a \a lower multiple of
/// KEYLENGTH_MULTIPLE.
virtual size_t GetValidKeyLength(size_t keylength) const =0;
/// \brief Returns whether keylength is a valid key length
/// \param keylength the requested keylength
/// \return true if keylength is valid, false otherwise
/// \details Internally the function calls GetValidKeyLength()
virtual bool IsValidKeyLength(size_t keylength) const
{return keylength == GetValidKeyLength(keylength);}
/// \brief Sets or reset the key of this object
/// \param key the key to use when keying the object
/// \param length the size of the key, in bytes
/// \param params additional initialization parameters to configure this object
virtual void SetKey(const byte *key, size_t length, const NameValuePairs ¶ms = g_nullNameValuePairs);
/// \brief Sets or reset the key of this object
/// \param key the key to use when keying the object
/// \param length the size of the key, in bytes
/// \param rounds the number of rounds to apply the transformation function,
/// if applicable
/// \details SetKeyWithRounds() calls SetKey() with a NameValuePairs
/// object that only specifies rounds. rounds is an integer parameter,
/// and <tt>-1</tt> means use the default number of rounds.
void SetKeyWithRounds(const byte *key, size_t length, int rounds);
/// \brief Sets or reset the key of this object
/// \param key the key to use when keying the object
/// \param length the size of the key, in bytes
/// \param iv the initialization vector to use when keying the object
/// \param ivLength the size of the iv, in bytes
/// \details SetKeyWithIV() calls SetKey() with a NameValuePairs
/// that only specifies IV. The IV is a byte buffer with size ivLength.
/// ivLength is an integer parameter, and <tt>-1</tt> means use IVSize().
void SetKeyWithIV(const byte *key, size_t length, const byte *iv, size_t ivLength);
/// \brief Sets or reset the key of this object
/// \param key the key to use when keying the object
/// \param length the size of the key, in bytes
/// \param iv the initialization vector to use when keying the object
/// \details SetKeyWithIV() calls SetKey() with a NameValuePairs() object
/// that only specifies iv. iv is a byte buffer, and it must have
/// a size IVSize().
void SetKeyWithIV(const byte *key, size_t length, const byte *iv)
{SetKeyWithIV(key, length, iv, IVSize());}
/// \brief Secure IVs requirements as enumerated values.
/// \details Provides secure IV requirements as a monotonically increasing enumerated values.
/// Requirements can be compared using less than (<) and greater than (>). For example,
/// <tt>UNIQUE_IV < RANDOM_IV</tt> and <tt>UNPREDICTABLE_RANDOM_IV > RANDOM_IV</tt>.
/// \details Objects that use SimpleKeyingInterface do not support an optional IV. That is,
/// an IV must be present or it must be absent. If you wish to support an optional IV then
/// provide two classes - one with an IV and one without an IV.
/// \sa IsResynchronizable(), CanUseRandomIVs(), CanUsePredictableIVs(), CanUseStructuredIVs()
enum IV_Requirement {
/// \brief The IV must be unique
UNIQUE_IV = 0,
/// \brief The IV must be random and possibly predictable
RANDOM_IV,
/// \brief The IV must be random and unpredictable
UNPREDICTABLE_RANDOM_IV,
/// \brief The IV is set by the object
INTERNALLY_GENERATED_IV,
/// \brief The object does not use an IV
NOT_RESYNCHRONIZABLE
};
/// \brief Minimal requirement for secure IVs
/// \return the secure IV requirement of the algorithm
virtual IV_Requirement IVRequirement() const =0;
/// \brief Determines if the object can be resynchronized
/// \return true if the object can be resynchronized (i.e. supports initialization vectors), false otherwise
/// \note If this function returns true, and no IV is passed to SetKey() and <tt>CanUseStructuredIVs()==true</tt>,
/// an IV of all 0's will be assumed.
bool IsResynchronizable() const {return IVRequirement() < NOT_RESYNCHRONIZABLE;}
/// \brief Determines if the object can use random IVs
/// \return true if the object can use random IVs (in addition to ones returned by GetNextIV), false otherwise
bool CanUseRandomIVs() const {return IVRequirement() <= UNPREDICTABLE_RANDOM_IV;}
/// \brief Determines if the object can use random but possibly predictable IVs
/// \return true if the object can use random but possibly predictable IVs (in addition to ones returned by
/// GetNextIV), false otherwise
bool CanUsePredictableIVs() const {return IVRequirement() <= RANDOM_IV;}
/// \brief Determines if the object can use structured IVs
/// \returns true if the object can use structured IVs, false otherwise
/// \details CanUseStructuredIVs() indicates whether the object can use structured IVs; for example a counter
/// (in addition to ones returned by GetNextIV).
bool CanUseStructuredIVs() const {return IVRequirement() <= UNIQUE_IV;}
/// \brief Returns length of the IV accepted by this object
/// \return the size of an IV, in bytes
/// \throws NotImplemented() if the object does not support resynchronization
/// \details The default implementation throws NotImplemented
virtual unsigned int IVSize() const
{throw NotImplemented(GetAlgorithm().AlgorithmName() + ": this object doesn't support resynchronization");}
/// \brief Provides the default size of an IV
/// \return default length of IVs accepted by this object, in bytes
unsigned int DefaultIVLength() const {return IVSize();}
/// \brief Provides the minimum size of an IV
/// \return minimal length of IVs accepted by this object, in bytes
/// \throws NotImplemented() if the object does not support resynchronization
virtual unsigned int MinIVLength() const {return IVSize();}
/// \brief Provides the maximum size of an IV
/// \return maximal length of IVs accepted by this object, in bytes
/// \throws NotImplemented() if the object does not support resynchronization
virtual unsigned int MaxIVLength() const {return IVSize();}
/// \brief Resynchronize with an IV
/// \param iv the initialization vector
/// \param ivLength the size of the initialization vector, in bytes
/// \details Resynchronize() resynchronizes with an IV provided by the caller. <tt>ivLength=-1</tt> means use IVSize().
/// \throws NotImplemented() if the object does not support resynchronization
virtual void Resynchronize(const byte *iv, int ivLength=-1) {
CRYPTOPP_UNUSED(iv); CRYPTOPP_UNUSED(ivLength);
throw NotImplemented(GetAlgorithm().AlgorithmName() + ": this object doesn't support resynchronization");
}
/// \brief Retrieves a secure IV for the next message
/// \param rng a RandomNumberGenerator to produce keying material
/// \param iv a block of bytes to receive the IV
/// \details The IV must be at least IVSize() in length.
/// \details This method should be called after you finish encrypting one message and are ready
/// to start the next one. After calling it, you must call SetKey() or Resynchronize().
/// before using this object again.
/// \details Internally, the base class implementation calls RandomNumberGenerator's GenerateBlock()
/// \note This method is not implemented on decryption objects.
virtual void GetNextIV(RandomNumberGenerator &rng, byte *iv);
protected: /// \brief Returns the base class Algorithm /// \return the base class Algorithm virtual const Algorithm & GetAlgorithm() const =0;
/// \brief Sets the key for this object without performing parameter validation
/// \param key a byte buffer used to key the cipher
/// \param length the length of the byte buffer
/// \param params additional parameters passed as NameValuePairs
/// \details key must be at least DEFAULT_KEYLENGTH in length.
virtual void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) =0;
/// \brief Validates the key length
/// \param length the size of the keying material, in bytes
/// \throws InvalidKeyLength if the key length is invalid
void ThrowIfInvalidKeyLength(size_t length);
/// \brief Validates the object
/// \throws InvalidArgument if the IV is present
/// \details Internally, the default implementation calls IsResynchronizable() and throws
/// InvalidArgument if the function returns true.
/// \note called when no IV is passed
void ThrowIfResynchronizable();
/// \brief Validates the IV
/// \param iv the IV with a length of IVSize, in bytes
/// \throws InvalidArgument on failure
/// \details Internally, the default implementation checks the iv. If iv is not NULL or nullptr,
/// then the function succeeds. If iv is NULL, then IVRequirement is checked against
/// UNPREDICTABLE_RANDOM_IV. If IVRequirement is UNPREDICTABLE_RANDOM_IV, then
/// then the function succeeds. Otherwise, an exception is thrown.
void ThrowIfInvalidIV(const byte *iv);
/// \brief Validates the IV length
/// \param length the size of an IV, in bytes
/// \throws InvalidArgument if the IV length is invalid
size_t ThrowIfInvalidIVLength(int length);
/// \brief Retrieves and validates the IV
/// \param params NameValuePairs with the IV supplied as a ConstByteArrayParameter
/// \param size the length of the IV, in bytes
/// \return a pointer to the first byte of the IV
/// \throws InvalidArgument if the number of rounds are invalid
const byte * GetIVAndThrowIfInvalid(const NameValuePairs ¶ms, size_t &size);
/// \brief Validates the key length
/// \param length the size of the keying material, in bytes
inline void AssertValidKeyLength(size_t length) const
{CRYPTOPP_UNUSED(length); CRYPTOPP_ASSERT(IsValidKeyLength(length));}
};
/// \brief Interface for the data processing part of block ciphers /// \details Classes derived from BlockTransformation are block ciphers /// in ECB mode (for example the DES::Encryption class), which are stateless. /// These classes should not be used directly, but only in combination with /// a mode class (see CipherModeDocumentation in modes.h). class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE BlockTransformation : public Algorithm { public: virtual ~BlockTransformation() {}
/// \brief Encrypt or decrypt a block
/// \param inBlock the input message before processing
/// \param outBlock the output message after processing
/// \param xorBlock an optional XOR mask
/// \details ProcessAndXorBlock encrypts or decrypts inBlock, xor with xorBlock, and write to outBlock.
/// \details The size of the block is determined by the block cipher and its documentation. Use
/// BLOCKSIZE at compile time, or BlockSize() at runtime.
/// \note The message can be transformed in-place, or the buffers must \a not overlap
/// \sa FixedBlockSize, BlockCipherFinal from seckey.h and BlockSize()
virtual void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const =0;
/// \brief Encrypt or decrypt a block
/// \param inBlock the input message before processing
/// \param outBlock the output message after processing
/// \details ProcessBlock encrypts or decrypts inBlock and write to outBlock.
/// \details The size of the block is determined by the block cipher and its documentation.
/// Use BLOCKSIZE at compile time, or BlockSize() at runtime.
/// \sa FixedBlockSize, BlockCipherFinal from seckey.h and BlockSize()
/// \note The message can be transformed in-place, or the buffers must \a not overlap
void ProcessBlock(const byte *inBlock, byte *outBlock) const
{ProcessAndXorBlock(inBlock, NULLPTR, outBlock);}
/// \brief Encrypt or decrypt a block in place
/// \param inoutBlock the input message before processing
/// \details ProcessBlock encrypts or decrypts inoutBlock in-place.
/// \details The size of the block is determined by the block cipher and its documentation.
/// Use BLOCKSIZE at compile time, or BlockSize() at runtime.
/// \sa FixedBlockSize, BlockCipherFinal from seckey.h and BlockSize()
void ProcessBlock(byte *inoutBlock) const
{ProcessAndXorBlock(inoutBlock, NULLPTR, inoutBlock);}
/// Provides the block size of the cipher
/// \return the block size of the cipher, in bytes
virtual unsigned int BlockSize() const =0;
/// \brief Provides input and output data alignment for optimal performance.
/// \return the input data alignment that provides optimal performance
/// \sa GetAlignment() and OptimalBlockSize()
virtual unsigned int OptimalDataAlignment() const;
/// \brief Determines if the transformation is a permutation
/// \returns true if this is a permutation (i.e. there is an inverse transformation)
virtual bool IsPermutation() const {return true;}
/// \brief Determines if the cipher is being operated in its forward direction
/// \returns true if DIR is ENCRYPTION, false otherwise
/// \sa IsForwardTransformation(), IsPermutation(), GetCipherDirection()
virtual bool IsForwardTransformation() const =0;
/// \brief Determines the number of blocks that can be processed in parallel
/// \return the number of blocks that can be processed in parallel, for bit-slicing implementations
/// \details Bit-slicing is often used to improve throughput and minimize timing attacks.
virtual unsigned int OptimalNumberOfParallelBlocks() const {return 1;}
/// \brief Bit flags that control AdvancedProcessBlocks() behavior
enum FlagsForAdvancedProcessBlocks {
/// \brief inBlock is a counter
BT_InBlockIsCounter=1,
/// \brief should not modify block pointers
BT_DontIncrementInOutPointers=2,
/// \brief Xor inputs before transformation
BT_XorInput=4,
/// \brief perform the transformation in reverse
BT_ReverseDirection=8,
/// \brief Allow parallel transformations
BT_AllowParallel=16};
/// \brief Encrypt and xor multiple blocks using additional flags
/// \param inBlocks the input message before processing
/// \param xorBlocks an optional XOR mask
/// \param outBlocks the output message after processing
/// \param length the size of the blocks, in bytes
/// \param flags additional flags to control processing
/// \details Encrypt and xor multiple blocks according to FlagsForAdvancedProcessBlocks flags.
/// \note If BT_InBlockIsCounter is set, then the last byte of inBlocks may be modified.
virtual size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const;
/// \brief Provides the direction of the cipher
/// \return ENCRYPTION if IsForwardTransformation() is true, DECRYPTION otherwise
/// \sa IsForwardTransformation(), IsPermutation()
inline CipherDir GetCipherDirection() const {return IsForwardTransformation() ? ENCRYPTION : DECRYPTION;}
};
/// \brief Interface for the data processing portion of stream ciphers /// \sa StreamTransformationFilter() class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE StreamTransformation : public Algorithm { public: virtual ~StreamTransformation() {}
/// \brief Provides a reference to this object
/// \return A reference to this object
/// \details Useful for passing a temporary object to a function that takes a non-const reference
StreamTransformation& Ref() {return *this;}
/// \brief Provides the mandatory block size of the cipher
/// \return The block size of the cipher if input must be processed in blocks, 1 otherwise
/// \details Stream ciphers and some block ciphers modes of operation return 1. Modes that
/// return 1 must be able to process a single byte at a time, like counter mode. If a
/// mode of operation or block cipher cannot stream then it must not return 1.
/// \details When filters operate the mode or cipher, ProcessData will be called with a
/// string of bytes that is determined by MandatoryBlockSize and OptimalBlockSize. When a
/// policy is set, like 16-byte strings for a 16-byte block cipher, the filter will buffer
/// bytes until the specified number of bytes is available to the object.
/// \sa ProcessData, ProcessLastBlock, MandatoryBlockSize, MinLastBlockSize, BlockPaddingSchemeDef, IsLastBlockSpecial
virtual unsigned int MandatoryBlockSize() const {return 1;}
/// \brief Provides the input block size most efficient for this cipher
/// \return The input block size that is most efficient for the cipher
/// \details The base class implementation returns MandatoryBlockSize().
/// \note Optimal input length is
/// <tt>n * OptimalBlockSize() - GetOptimalBlockSizeUsed()</tt> for any <tt>n \> 0</tt>.
virtual unsigned int OptimalBlockSize() const {return MandatoryBlockSize();}
/// \brief Provides the number of bytes used in the current block when processing at optimal block size.
/// \return the number of bytes used in the current block when processing at the optimal block size
virtual unsigned int GetOptimalBlockSizeUsed() const {return 0;}
/// \brief Provides input and output data alignment for optimal performance
/// \return the input data alignment that provides optimal performance
/// \sa GetAlignment() and OptimalBlockSize()
virtual unsigned int OptimalDataAlignment() const;
/// \brief Encrypt or decrypt an array of bytes
/// \param outString the output byte buffer
/// \param inString the input byte buffer
/// \param length the size of the input and output byte buffers, in bytes
/// \details ProcessData is called with a string of bytes whose size depends on MandatoryBlockSize.
/// Either <tt>inString == outString</tt>, or they must not overlap.
/// \sa ProcessData, ProcessLastBlock, MandatoryBlockSize, MinLastBlockSize, BlockPaddingSchemeDef, IsLastBlockSpecial
virtual void ProcessData(byte *outString, const byte *inString, size_t length) =0;
/// \brief Encrypt or decrypt the last block of data
/// \param outString the output byte buffer
/// \param outLength the size of the output byte buffer, in bytes
/// \param inString the input byte buffer
/// \param inLength the size of the input byte buffer, in bytes
/// \returns the number of bytes used in outString
/// \details ProcessLastBlock is used when the last block of data is special and requires handling
/// by the cipher. The current implementation provides an output buffer with a size
/// <tt>inLength+2*MandatoryBlockSize()</tt>. The return value allows the cipher to expand cipher
/// text during encryption or shrink plain text during decryption.
/// \details This member function is used by CBC-CTS and OCB modes.
/// \sa ProcessData, ProcessLastBlock, MandatoryBlockSize, MinLastBlockSize, BlockPaddingSchemeDef, IsLastBlockSpecial
virtual size_t ProcessLastBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength);
/// \brief Provides the size of the last block
/// \returns the minimum size of the last block
/// \details MinLastBlockSize() returns the minimum size of the last block. 0 indicates the last
/// block is not special.
/// \details MandatoryBlockSize() enlists one of two behaviors. First, if MandatoryBlockSize()
/// returns 1, then the cipher can be streamed and ProcessData() is called with the tail bytes.
/// Second, if MandatoryBlockSize() returns non-0, then the string of bytes is padded to
/// MandatoryBlockSize() according to the padding mode. Then, ProcessData() is called with the
/// padded string of bytes.
/// \details Some authenticated encryption modes are not expressed well with MandatoryBlockSize()
/// and MinLastBlockSize(). For example, AES/OCB uses 16-byte blocks (MandatoryBlockSize = 16)
/// and the last block requires special processing (MinLastBlockSize = 0). However, 0 is a valid
/// last block size for OCB and the special processing is custom padding, and not standard PKCS
/// padding. In response an unambiguous IsLastBlockSpecial() was added.
/// \sa ProcessData, ProcessLastBlock, MandatoryBlockSize, MinLastBlockSize, BlockPaddingSchemeDef, IsLastBlockSpecial
virtual unsigned int MinLastBlockSize() const {return 0;}
/// \brief Determines if the last block receives special processing
/// \returns true if the last block reveives special processing, false otherwise.
/// \details Some authenticated encryption modes are not expressed well with
/// MandatoryBlockSize() and MinLastBlockSize(). For example, AES/OCB uses
/// 16-byte blocks (MandatoryBlockSize = 16) and the last block requires special processing
/// (MinLastBlockSize = 0). However, 0 is a valid last block size for OCB and the special
/// processing is custom padding, and not standard PKCS padding. In response an
/// unambiguous IsLastBlockSpecial() was added.
/// \details When IsLastBlockSpecial() returns false nothing special happens. All the former
/// rules and behaviors apply. This is the default behavior of IsLastBlockSpecial().
/// \details When IsLastBlockSpecial() returns true four things happen. First, MinLastBlockSize = 0
/// means 0 is a valid block size that should be processed. Second, standard block cipher padding is
/// \a not \a applied. Third, the caller supplies an outString is larger than inString by
/// <tt>2*MandatoryBlockSize()</tt>. That is, there's a reserve available when processing the last block.
/// Fourth, the cipher is responsible for finalization like custom padding. The cipher will tell
/// the library how many bytes were processed or used by returning the appropriate value from
/// ProcessLastBlock().
/// \details The return value of ProcessLastBlock() indicates how many bytes were written to
/// <tt>outString</tt>. A filter pipelining data will send <tt>outString</tt> and up to <tt>outLength</tt>
/// to an <tt>AttachedTransformation()</tt> for additional processing. Below is an example of the code
/// used in <tt>StreamTransformationFilter::LastPut</tt>.
/// <pre> if (m_cipher.IsLastBlockSpecial())
/// {
/// size_t reserve = 2*m_cipher.MandatoryBlockSize();
/// space = HelpCreatePutSpace(*AttachedTransformation(), DEFAULT_CHANNEL, length+reserve);
/// length = m_cipher.ProcessLastBlock(space, length+reserve, inString, length);
/// AttachedTransformation()->Put(space, length);
/// return;
/// }</pre>
/// \sa ProcessData, ProcessLastBlock, MandatoryBlockSize, MinLastBlockSize, BlockPaddingSchemeDef, IsLastBlockSpecial
/// \since Crypto++ 6.0
virtual bool IsLastBlockSpecial() const {return false;}
/// \brief Encrypt or decrypt a string of bytes
/// \param inoutString the string to process
/// \param length the size of the inoutString, in bytes
/// \details Internally, the base class implementation calls ProcessData().
inline void ProcessString(byte *inoutString, size_t length)
{ProcessData(inoutString, inoutString, length);}
/// \brief Encrypt or decrypt a string of bytes
/// \param outString the output string to process
/// \param inString the input string to process
/// \param length the size of the input and output strings, in bytes
/// \details Internally, the base class implementation calls ProcessData().
inline void ProcessString(byte *outString, const byte *inString, size_t length)
{ProcessData(outString, inString, length);}
/// \brief Encrypt or decrypt a byte
/// \param input the input byte to process
/// \details Internally, the base class implementation calls ProcessData() with a size of 1.
inline byte ProcessByte(byte input)
{ProcessData(&input, &input, 1); return input;}
/// \brief Determines whether the cipher supports random access
/// \returns true if the cipher supports random access, false otherwise
virtual bool IsRandomAccess() const =0;
/// \brief Seek to an absolute position
/// \param pos position to seek
/// \throws NotImplemented
/// \details The base class implementation throws NotImplemented. The function
/// \ref CRYPTOPP_ASSERT "asserts" IsRandomAccess() in debug builds.
virtual void Seek(lword pos)
{
CRYPTOPP_UNUSED(pos);
CRYPTOPP_ASSERT(!IsRandomAccess());
throw NotImplemented("StreamTransformation: this object doesn't support random access");
}
/// \brief Determines whether the cipher is self-inverting
/// \returns true if the cipher is self-inverting, false otherwise
/// \details IsSelfInverting determines whether this transformation is
/// self-inverting (e.g. xor with a keystream).
virtual bool IsSelfInverting() const =0;
/// \brief Determines if the cipher is being operated in its forward direction
/// \returns true if DIR is ENCRYPTION, false otherwise
/// \sa IsForwardTransformation(), IsPermutation(), GetCipherDirection()
virtual bool IsForwardTransformation() const =0;
};
/// \brief Interface for hash functions and data processing part of MACs /// \details HashTransformation objects are stateful. They are created in an initial state, /// change state as Update() is called, and return to the initial /// state when Final() is called. This interface allows a large message to /// be hashed in pieces by calling Update() on each piece followed by /// calling Final(). /// \sa HashFilter(), HashVerificationFilter() class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE HashTransformation : public Algorithm { public: virtual ~HashTransformation() {}
/// \brief Provides a reference to this object
/// \return A reference to this object
/// \details Useful for passing a temporary object to a function that takes a non-const reference
HashTransformation& Ref() {return *this;}
/// \brief Updates a hash with additional input
/// \param input the additional input as a buffer
/// \param length the size of the buffer, in bytes
virtual void Update(const byte *input, size_t length) =0;
/// \brief Request space which can be written into by the caller
/// \param size the requested size of the buffer
/// \details The purpose of this method is to help avoid extra memory allocations.
/// \details size is an \a IN and \a OUT parameter and used as a hint. When the call is made,
/// size is the requested size of the buffer. When the call returns, size is the size of
/// the array returned to the caller.
/// \details The base class implementation sets size to 0 and returns NULL or nullptr.
/// \note Some objects, like ArraySink, cannot create a space because its fixed.
virtual byte * CreateUpdateSpace(size_t &size) {size=0; return NULLPTR;}
/// \brief Computes the hash of the current message
/// \param digest a pointer to the buffer to receive the hash
/// \details Final() restarts the hash for a new message.
/// \pre <tt>COUNTOF(digest) == DigestSize()</tt> or <tt>COUNTOF(digest) == HASH::DIGESTSIZE</tt> ensures
/// the output byte buffer is large enough for the digest.
virtual void Final(byte *digest)
{TruncatedFinal(digest, DigestSize());}
/// \brief Restart the hash
/// \details Discards the current state, and restart for a new message
virtual void Restart()
{TruncatedFinal(NULLPTR, 0);}
/// Provides the digest size of the hash
/// \return the digest size of the hash.
virtual unsigned int DigestSize() const =0;
/// Provides the tag size of the hash
/// \return the tag size of the hash.
/// \details Same as DigestSize().
unsigned int TagSize() const {return DigestSize();}
/// \brief Provides the block size of the compression function
/// \return block size of the compression function, in bytes
/// \details BlockSize() will return 0 if the hash is not block based
/// or does not have an equivalent block size. For example, Keccak
/// and SHA-3 do not have a block size, but they do have an equivalent
/// block size called rate expressed as <tt>r</tt>.
virtual unsigned int BlockSize() const {return 0;}
/// \brief Provides the input block size most efficient for this hash.
/// \return The input block size that is most efficient for the cipher
/// \details The base class implementation returns MandatoryBlockSize().
/// \details Optimal input length is
/// <tt>n * OptimalBlockSize() - GetOptimalBlockSizeUsed()</tt> for any <tt>n \> 0</tt>.
virtual unsigned int OptimalBlockSize() const {return 1;}
/// \brief Provides input and output data alignment for optimal performance
/// \return the input data alignment that provides optimal performance
/// \sa GetAlignment() and OptimalBlockSize()
virtual unsigned int OptimalDataAlignment() const;
/// \brief Updates the hash with additional input and computes the hash of the current message
/// \param digest a pointer to the buffer to receive the hash
/// \param input the additional input as a buffer
/// \param length the size of the buffer, in bytes
/// \details Use this if your input is in one piece and you don't want to call Update()
/// and Final() separately
/// \details CalculateDigest() restarts the hash for the next message.
/// \pre <tt>COUNTOF(digest) == DigestSize()</tt> or <tt>COUNTOF(digest) == HASH::DIGESTSIZE</tt> ensures
/// the output byte buffer is large enough for the digest.
virtual void CalculateDigest(byte *digest, const byte *input, size_t length)
{Update(input, length); Final(digest);}
/// \brief Verifies the hash of the current message
/// \param digest a pointer to the buffer of an \a existing hash
/// \return \p true if the existing hash matches the computed hash, \p false otherwise
/// \throws ThrowIfInvalidTruncatedSize() if the existing hash's size exceeds DigestSize()
/// \details Verify() performs a bitwise compare on the buffers using VerifyBufsEqual(), which is
/// a constant time comparison function. digestLength cannot exceed DigestSize().
/// \details Verify() restarts the hash for the next message.
/// \pre <tt>COUNTOF(digest) == DigestSize()</tt> or <tt>COUNTOF(digest) == HASH::DIGESTSIZE</tt> ensures
/// the output byte buffer is large enough for the digest.
virtual bool Verify(const byte *digest)
{return TruncatedVerify(digest, DigestSize());}
/// \brief Updates the hash with additional input and verifies the hash of the current message
/// \param digest a pointer to the buffer of an \a existing hash
/// \param input the additional input as a buffer
/// \param length the size of the buffer, in bytes
/// \return \p true if the existing hash matches the computed hash, \p false otherwise
/// \throws ThrowIfInvalidTruncatedSize() if the existing hash's size exceeds DigestSize()
/// \details Use this if your input is in one piece and you don't want to call Update()
/// and Verify() separately
/// \details VerifyDigest() performs a bitwise compare on the buffers using VerifyBufsEqual(),
/// which is a constant time comparison function. digestLength cannot exceed DigestSize().
/// \details VerifyDigest() restarts the hash for the next message.
/// \pre <tt>COUNTOF(digest) == DigestSize()</tt> or <tt>COUNTOF(digest) == HASH::DIGESTSIZE</tt> ensures
/// the output byte buffer is large enough for the digest.
virtual bool VerifyDigest(const byte *digest, const byte *input, size_t length)
{Update(input, length); return Verify(digest);}
/// \brief Computes the hash of the current message
/// \param digest a pointer to the buffer to receive the hash
/// \param digestSize the size of the truncated digest, in bytes
/// \details TruncatedFinal() call Final() and then copies digestSize bytes to digest.
/// The hash is restarted the hash for the next message.
virtual void TruncatedFinal(byte *digest, size_t digestSize) =0;
/// \brief Updates the hash with additional input and computes the hash of the current message
/// \param digest a pointer to the buffer to receive the hash
/// \param digestSize the length of the truncated hash, in bytes
/// \param input the additional input as a buffer
/// \param length the size of the buffer, in bytes
/// \details Use this if your input is in one piece and you don't want to call Update()
/// and CalculateDigest() separately.
/// \details CalculateTruncatedDigest() restarts the hash for the next message.
/// \pre <tt>COUNTOF(digest) == DigestSize()</tt> or <tt>COUNTOF(digest) == HASH::DIGESTSIZE</tt> ensures
/// the output byte buffer is large enough for the digest.
virtual void CalculateTruncatedDigest(byte *digest, size_t digestSize, const byte *input, size_t length)
{Update(input, length); TruncatedFinal(digest, digestSize);}
/// \brief Verifies the hash of the current message
/// \param digest a pointer to the buffer of an \a existing hash
/// \param digestLength the size of the truncated hash, in bytes
/// \return \p true if the existing hash matches the computed hash, \p false otherwise
/// \throws ThrowIfInvalidTruncatedSize() if digestLength exceeds DigestSize()
/// \details TruncatedVerify() is a truncated version of Verify(). It can operate on a
/// buffer smaller than DigestSize(). However, digestLength cannot exceed DigestSize().
/// \details Verify() performs a bitwise compare on the buffers using VerifyBufsEqual(), which is
/// a constant time comparison function. digestLength cannot exceed DigestSize().
/// \details TruncatedVerify() restarts the hash for the next message.
virtual bool TruncatedVerify(const byte *digest, size_t digestLength);
/// \brief Updates the hash with additional input and verifies the hash of the current message
/// \param digest a pointer to the buffer of an \a existing hash
/// \param digestLength the size of the truncated hash, in bytes
/// \param input the additional input as a buffer
/// \param length the size of the buffer, in bytes
/// \return \p true if the existing hash matches the computed hash, \p false otherwise
/// \throws ThrowIfInvalidTruncatedSize() if digestLength exceeds DigestSize()
/// \details Use this if your input is in one piece and you don't want to call Update()
/// and TruncatedVerify() separately.
/// \details VerifyTruncatedDigest() is a truncated version of VerifyDigest(). It can operate
/// on a buffer smaller than DigestSize(). However, digestLength cannot exceed DigestSize().
/// \details VerifyTruncatedDigest() restarts the hash for the next message.
/// \pre <tt>COUNTOF(digest) == DigestSize()</tt> or <tt>COUNTOF(digest) == HASH::DIGESTSIZE</tt> ensures
/// the output byte buffer is large enough for the digest.
virtual bool VerifyTruncatedDigest(const byte *digest, size_t digestLength, const byte *input, size_t length)
{Update(input, length); return TruncatedVerify(digest, digestLength);}
protected: /// \brief Validates a truncated digest size /// \param size the requested digest size /// \throws InvalidArgument if the algorithm's digest size cannot be truncated to the requested size /// \details Throws an exception when the truncated digest size is greater than DigestSize() void ThrowIfInvalidTruncatedSize(size_t size) const; };
/// \brief Interface for one direction (encryption or decryption) of a block cipher /// \details These objects usually should not be used directly. See BlockTransformation for more details. class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE BlockCipher : public SimpleKeyingInterface, public BlockTransformation { protected: const Algorithm & GetAlgorithm() const {return *this;} };
/// \brief Interface for one direction (encryption or decryption) of a stream cipher or cipher mode /// \details These objects usually should not be used directly. See StreamTransformation for more details. class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE SymmetricCipher : public SimpleKeyingInterface, public StreamTransformation { protected: const Algorithm & GetAlgorithm() const {return *this;} };
/// \brief Interface for message authentication codes /// \details These objects usually should not be used directly. See HashTransformation for more details. class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE MessageAuthenticationCode : public SimpleKeyingInterface, public HashTransformation { protected: const Algorithm & GetAlgorithm() const {return *this;} };
/// \brief Interface for authenticated encryption modes of operation /// \details AuthenticatedSymmetricCipher() provides the interface for one direction /// (encryption or decryption) of a stream cipher or block cipher mode with authentication. The /// StreamTransformation() part of this interface is used to encrypt or decrypt the data. The /// MessageAuthenticationCode() part of the interface is used to input additional authenticated /// data (AAD), which is MAC'ed but not encrypted. The MessageAuthenticationCode() part is also /// used to generate and verify the MAC. /// \details Crypto++ provides four authenticated encryption modes of operation - CCM, EAX, GCM /// and OCB mode. All modes implement AuthenticatedSymmetricCipher() and the motivation for /// the API, like calling AAD a "header", can be found in Bellare, Rogaway and /// Wagner's The EAX Mode of /// Operation. The EAX paper suggested a basic API to help standardize AEAD schemes in /// software and promote adoption of the modes. /// \sa Authenticated /// Encryption on the Crypto++ wiki. /// \since Crypto++ 5.6.0 class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE AuthenticatedSymmetricCipher : public MessageAuthenticationCode, public StreamTransformation { public: virtual ~AuthenticatedSymmetricCipher() {}
/// \brief Exception thrown when the object is in the wrong state for the operation
/// \details this indicates that a member function was called in the wrong state, for example trying to encrypt
/// a message before having set the key or IV
class BadState : public Exception
{
public:
explicit BadState(const std::string &name, const char *message) : Exception(OTHER_ERROR, name + ": " + message) {}
explicit BadState(const std::string &name, const char *function, const char *state) : Exception(OTHER_ERROR, name + ": " + function + " was called before " + state) {}
};
/// \brief Provides the maximum length of AAD that can be input
/// \return the maximum length of AAD that can be input before the encrypted data
virtual lword MaxHeaderLength() const =0;
/// \brief Provides the maximum length of encrypted data
/// \return the maximum length of encrypted data
virtual lword MaxMessageLength() const =0;
/// \brief Provides the the maximum length of AAD
/// \return the maximum length of AAD that can be input after the encrypted data
virtual lword MaxFooterLength() const {return 0;}
/// \brief Determines if data lengths must be specified prior to inputting data
/// \return true if the data lengths are required before inputting data, false otherwise
/// \details if this function returns true, SpecifyDataLengths() must be called before attempting to input data.
/// This is the case for some schemes, such as CCM.
/// \sa SpecifyDataLengths()
virtual bool NeedsPrespecifiedDataLengths() const {return false;}
/// \brief Prescribes the data lengths
/// \param headerLength size of data before message is input, in bytes
/// \param messageLength size of the message, in bytes
/// \param footerLength size of data after message is input, in bytes
/// \details SpecifyDataLengths() only needs to be called if NeedsPrespecifiedDataLengths() returns <tt>true</tt>.
/// If <tt>true</tt>, then <tt>headerLength</tt> will be validated against <tt>MaxHeaderLength()</tt>,
/// <tt>messageLength</tt> will be validated against <tt>MaxMessageLength()</tt>, and
/// <tt>footerLength</tt> will be validated against <tt>MaxFooterLength()</tt>.
/// \sa NeedsPrespecifiedDataLengths()
void SpecifyDataLengths(lword headerLength, lword messageLength, lword footerLength=0);
/// \brief Encrypts and calculates a MAC in one call
/// \param ciphertext the encryption buffer
/// \param mac the mac buffer
/// \param macSize the size of the MAC buffer, in bytes
/// \param iv the iv buffer
/// \param ivLength the size of the IV buffer, in bytes
/// \param header the AAD buffer
/// \param headerLength the size of the AAD buffer, in bytes
/// \param message the message buffer
/// \param messageLength the size of the messagetext buffer, in bytes
/// \details EncryptAndAuthenticate() encrypts and generates the MAC in one call. The function
/// truncates the MAC if <tt>macSize < TagSize()</tt>.
virtual void EncryptAndAuthenticate(byte *ciphertext, byte *mac, size_t macSize, const byte *iv, int ivLength, const byte *header, size_t headerLength, const byte *message, size_t messageLength);
/// \brief Decrypts and verifies a MAC in one call
/// \param message the decryption buffer
/// \param mac the mac buffer
/// \param macSize the size of the MAC buffer, in bytes
/// \param iv the iv buffer
/// \param ivLength the size of the IV buffer, in bytes
/// \param header the AAD buffer
/// \param headerLength the size of the AAD buffer, in bytes
/// \param ciphertext the ciphertext buffer
/// \param ciphertextLength the size of the ciphertext buffer, in bytes
/// \return true if the MAC is valid and the decoding succeeded, false otherwise
/// \details DecryptAndVerify() decrypts and verifies the MAC in one call.
/// <tt>message</tt> is a decryption buffer and should be at least as large as the ciphertext buffer.
/// \details The function returns true iff MAC is valid. DecryptAndVerify() assumes the MAC
/// is truncated if <tt>macLength < TagSize()</tt>.
virtual bool DecryptAndVerify(byte *message, const byte *mac, size_t macSize, const byte *iv, int ivLength, const byte *header, size_t headerLength, const byte *ciphertext, size_t ciphertextLength);
/// \brief Provides the name of this algorithm
/// \return the standard algorithm name
/// \details The standard algorithm name can be a name like \a AES or \a AES/GCM. Some algorithms
/// do not have standard names yet. For example, there is no standard algorithm name for
/// Shoup's ECIES.
virtual std::string AlgorithmName() const;
protected: const Algorithm & GetAlgorithm() const {return *static_cast<const MessageAuthenticationCode *>(this);} virtual void UncheckedSpecifyDataLengths(lword headerLength, lword messageLength, lword footerLength) {CRYPTOPP_UNUSED(headerLength); CRYPTOPP_UNUSED(messageLength); CRYPTOPP_UNUSED(footerLength);} };
/// \brief Interface for random number generators /// \details The library provides a number of random number generators, from software based /// to hardware based generators. /// \details All generated values are uniformly distributed over the range specified. /// \since Crypto++ 3.1 class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE RandomNumberGenerator : public Algorithm { public: virtual ~RandomNumberGenerator() {}
/// \brief Update RNG state with additional unpredictable values
/// \param input the entropy to add to the generator
/// \param length the size of the input buffer
/// \throws NotImplemented
/// \details A generator may or may not accept additional entropy. Call CanIncorporateEntropy()
/// to test for the ability to use additional entropy.
/// \details If a derived class does not override IncorporateEntropy(), then the base class
/// throws NotImplemented.
virtual void IncorporateEntropy(const byte *input, size_t length)
{
CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(length);
throw NotImplemented("RandomNumberGenerator: IncorporateEntropy not implemented");
}
/// \brief Determines if a generator can accept additional entropy
/// \return true if IncorporateEntropy() is implemented
virtual bool CanIncorporateEntropy() const {return false;}
/// \brief Generate new random byte and return it
/// \return a random 8-bit byte
/// \details Default implementation calls GenerateBlock() with one byte.
/// \details All generated values are uniformly distributed over the range specified within the
/// the constraints of a particular generator.
virtual byte GenerateByte();
/// \brief Generate new random bit and return it
/// \return a random bit
/// \details The default implementation calls GenerateByte() and return its lowest bit.
/// \details All generated values are uniformly distributed over the range specified within the
/// the constraints of a particular generator.
virtual unsigned int GenerateBit();
/// \brief Generate a random 32 bit word in the range min to max, inclusive
/// \param min the lower bound of the range
/// \param max the upper bound of the range
/// \return a random 32-bit word
/// \details The default implementation calls Crop() on the difference between max and
/// min, and then returns the result added to min.
/// \details All generated values are uniformly distributed over the range specified within the
/// the constraints of a particular generator.
virtual word32 GenerateWord32(word32 min=0, word32 max=0xffffffffUL);
/// \brief Generate random array of bytes
/// \param output the byte buffer
/// \param size the length of the buffer, in bytes
/// \details All generated values are uniformly distributed over the range specified within the
/// the constraints of a particular generator.
/// \note A derived generator \a must override either GenerateBlock() or
/// GenerateIntoBufferedTransformation(). They can override both, or have one call the other.
virtual void GenerateBlock(byte *output, size_t size);
/// \brief Generate random bytes into a BufferedTransformation
/// \param target the BufferedTransformation object which receives the bytes
/// \param channel the channel on which the bytes should be pumped
/// \param length the number of bytes to generate
/// \details The default implementation calls GenerateBlock() and pumps the result into
/// the DEFAULT_CHANNEL of the target.
/// \details All generated values are uniformly distributed over the range specified within the
/// the constraints of a particular generator.
/// \note A derived generator \a must override either GenerateBlock() or
/// GenerateIntoBufferedTransformation(). They can override both, or have one call the other.
virtual void GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword length);
/// \brief Generate and discard n bytes
/// \param n the number of bytes to generate and discard
virtual void DiscardBytes(size_t n);
/// \brief Randomly shuffle the specified array
/// \param begin an iterator to the first element in the array
/// \param end an iterator beyond the last element in the array
/// \details The resulting permutation is uniformly distributed.
template <class IT> void Shuffle(IT begin, IT end)
{
// TODO: What happens if there are more than 2^32 elements?
for (; begin != end; ++begin)
std::iter_swap(begin, begin + GenerateWord32(0, static_cast<word32>(end-begin-1)));
}
};
/// \brief Interface for key derivation functions /// \since Crypto++ 7.0 class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE KeyDerivationFunction : public Algorithm { public: virtual ~KeyDerivationFunction() {}
/// \brief Provides the name of this algorithm
/// \return the standard algorithm name
virtual std::string AlgorithmName() const =0;
/// \brief Determine minimum number of bytes
/// \returns Minimum number of bytes which can be derived
virtual size_t MinDerivedLength() const;
/// \brief Determine maximum number of bytes
/// \returns Maximum number of bytes which can be derived
virtual size_t MaxDerivedLength() const;
/// \brief Returns a valid key length for the derivation function
/// \param keylength the size of the derived key, in bytes
/// \returns the valid key length, in bytes
virtual size_t GetValidDerivedLength(size_t keylength) const =0;
/// \brief Returns whether keylength is a valid key length
/// \param keylength the requested keylength
/// \return true if the derived keylength is valid, false otherwise
/// \details Internally the function calls GetValidKeyLength()
virtual bool IsValidDerivedLength(size_t keylength) const {
return keylength == GetValidDerivedLength(keylength);
}
/// \brief Derive a key from a seed
/// \param derived the derived output buffer
/// \param derivedLen the size of the derived buffer, in bytes
/// \param secret the seed input buffer
/// \param secretLen the size of the secret buffer, in bytes
/// \param params additional initialization parameters to configure this object
/// \returns the number of iterations performed
/// \throws InvalidDerivedLength if <tt>derivedLen</tt> is invalid for the scheme
/// \details DeriveKey() provides a standard interface to derive a key from
/// a secret seed and other parameters. Each class that derives from KeyDerivationFunction
/// provides an overload that accepts most parameters used by the derivation function.
/// \details the number of iterations performed by DeriveKey() may be 1. For example, a
/// scheme like HKDF does not use the iteration count so it returns 1.
virtual size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, const NameValuePairs& params = g_nullNameValuePairs) const =0;
/// \brief Set or change parameters
/// \param params additional initialization parameters to configure this object
/// \details SetParameters() is useful for setting common parameters when an object is
/// reused. Some derivation function classes may choose to implement it.
virtual void SetParameters(const NameValuePairs& params);
protected: /// \brief Returns the base class Algorithm /// \return the base class Algorithm virtual const Algorithm & GetAlgorithm() const =0;
/// \brief Validates the derived key length
/// \param length the size of the derived key material, in bytes
/// \throws InvalidKeyLength if the key length is invalid
void ThrowIfInvalidDerivedLength(size_t length) const;
};
/// \brief Interface for password based key derivation functions /// \since Crypto++ 7.0 struct PasswordBasedKeyDerivationFunction : public KeyDerivationFunction { };
/// \brief Random Number Generator that does not produce random numbers /// \return reference that can be passed to functions that require a RandomNumberGenerator /// \details NullRNG() returns a reference that can be passed to functions that require a /// RandomNumberGenerator but don't actually use it. The NullRNG() throws NotImplemented /// when a generation function is called. /// \sa ClassNullRNG, PK_SignatureScheme::IsProbabilistic() CRYPTOPP_DLL RandomNumberGenerator & CRYPTOPP_API NullRNG();
class WaitObjectContainer; class CallStack;
/// \brief Interface for objects that can be waited on. class CRYPTOPP_NO_VTABLE Waitable { public: virtual ~Waitable() {}
/// \brief Maximum number of wait objects that this object can return
/// \return the maximum number of wait objects
virtual unsigned int GetMaxWaitObjectCount() const =0;
/// \brief Retrieves waitable objects
/// \param container the wait container to receive the references to the objects.
/// \param callStack CallStack() object used to select waitable objects
/// \details GetWaitObjects() is usually called in one of two ways. First, it can
/// be called like <tt>something.GetWaitObjects(c, CallStack("my func after X", 0));</tt>.
/// Second, if in an outer GetWaitObjects() method that itself takes a callStack
/// parameter, it can be called like
/// <tt>innerThing.GetWaitObjects(c, CallStack("MyClass::GetWaitObjects at X", &callStack));</tt>.
virtual void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack) =0;
/// \brief Wait on this object
/// \return true if the wait succeeded, false otherwise
/// \details Wait() is the same as creating an empty container, calling GetWaitObjects(), and then calling
/// Wait() on the container.
bool Wait(unsigned long milliseconds, CallStack const& callStack);
};
/// \brief Interface for buffered transformations /// \details BufferedTransformation is a generalization of BlockTransformation, /// StreamTransformation and HashTransformation. /// \details A buffered transformation is an object that takes a stream of bytes as input (this may /// be done in stages), does some computation on them, and then places the result into an internal /// buffer for later retrieval. Any partial result already in the output buffer is not modified /// by further input. /// \details If a method takes a "blocking" parameter, and you pass false for it, then the method /// will return before all input has been processed if the input cannot be processed without waiting /// (for network buffers to become available, for example). In this case the method will return true /// or a non-zero integer value. When this happens you must continue to call the method with the same /// parameters until it returns false or zero, before calling any other method on it or attached /// /p BufferedTransformation. The integer return value in this case is approximately /// the number of bytes left to be processed, and can be used to implement a progress bar. /// \details For functions that take a "propagation" parameter, propagation != 0 means pass on /// the signal to attached BufferedTransformation objects, with propagation decremented at each /// step until it reaches 0. -1 means unlimited propagation. /// \details \a All of the retrieval functions, like Get() and GetWord32(), return the actual /// number of bytes retrieved, which is the lesser of the request number and MaxRetrievable(). /// \details \a Most of the input functions, like Put() and PutWord32(), return the number of /// bytes remaining to be processed. A 0 value means all bytes were processed, and a non-0 value /// means bytes remain to be processed. /// \nosubgrouping class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE BufferedTransformation : public Algorithm, public Waitable { public: virtual ~BufferedTransformation() {}
/// \brief Construct a BufferedTransformation
BufferedTransformation() : Algorithm(false) {}
/// \brief Provides a reference to this object
/// \return A reference to this object
/// \details Useful for passing a temporary object to a function that takes a non-const reference
BufferedTransformation& Ref() {return *this;}
/// \name INPUT
//@{
/// \brief Input a byte for processing
/// \param inByte the 8-bit byte (octet) to be processed.
/// \param blocking specifies whether the object should block when processing input.
/// \return the number of bytes that remain in the block (i.e., bytes not processed). 0 indicates all
/// bytes were processed.
/// \details <tt>Put(byte)</tt> calls <tt>Put(byte*, size_t)</tt>.
size_t Put(byte inByte, bool blocking=true)
{return Put(&inByte, 1, blocking);}
/// \brief Input a byte buffer for processing
/// \param inString the byte buffer to process
/// \param length the size of the string, in bytes
/// \param blocking specifies whether the object should block when processing input
/// \return the number of bytes that remain in the block (i.e., bytes not processed). 0 indicates all
/// bytes were processed.
/// \details Internally, Put() calls Put2().
size_t Put(const byte *inString, size_t length, bool blocking=true)
{return Put2(inString, length, 0, blocking);}
/// Input a 16-bit word for processing.
/// \param value the 16-bit value to be processed
/// \param order the ByteOrder of the value to be processed.
/// \param blocking specifies whether the object should block when processing input
/// \return the number of bytes that remain in the block (i.e., bytes not processed). 0 indicates all
/// bytes were processed.
size_t PutWord16(word16 value, ByteOrder order=BIG_ENDIAN_ORDER, bool blocking=true);
/// Input a 32-bit word for processing.
/// \param value the 32-bit value to be processed.
/// \param order the ByteOrder of the value to be processed.
/// \param blocking specifies whether the object should block when processing input.
/// \return the number of bytes that remain in the block (i.e., bytes not processed). 0 indicates all
/// bytes were processed.
size_t PutWord32(word32 value, ByteOrder order=BIG_ENDIAN_ORDER, bool blocking=true);
/// \brief Request space which can be written into by the caller
/// \param size the requested size of the buffer
/// \return byte pointer to the space to input data
/// \details The purpose of this method is to help avoid extra memory allocations.
/// \details size is an \a IN and \a OUT parameter and used as a hint. When the call is made,
/// size is the requested size of the buffer. When the call returns, size is the size of
/// the array returned to the caller.
/// \details The base class implementation sets size to 0 and returns NULL.
/// \note Some objects, like ArraySink, cannot create a space because its fixed. In the case of
/// an ArraySink, the pointer to the array is returned and the size is remaining size.
virtual byte * CreatePutSpace(size_t &size)
{size=0; return NULLPTR;}
/// \brief Determines whether input can be modified by the callee
/// \return true if input can be modified, false otherwise
/// \details The base class implementation returns false.
virtual bool CanModifyInput() const
{return false;}
/// \brief Input multiple bytes that may be modified by callee.
/// \param inString the byte buffer to process
/// \param length the size of the string, in bytes
/// \param blocking specifies whether the object should block when processing input
/// \return the number of bytes that remain in the block (i.e., bytes not processed). 0 indicates all
/// bytes were processed.
size_t PutModifiable(byte *inString, size_t length, bool blocking=true)
{return PutModifiable2(inString, length, 0, blocking);}
/// \brief Signals the end of messages to the object
/// \param propagation the number of attached transformations the MessageEnd() signal should be passed
/// \param blocking specifies whether the object should block when processing input
/// \details propagation count includes this object. Setting propagation to <tt>1</tt> means this
/// object only. Setting propagation to <tt>-1</tt> means unlimited propagation.
bool MessageEnd(int propagation=-1, bool blocking=true)
{return !!Put2(NULLPTR, 0, propagation < 0 ? -1 : propagation+1, blocking);}
/// \brief Input multiple bytes for processing and signal the end of a message
/// \param inString the byte buffer to process
/// \param length the size of the string, in bytes
/// \param propagation the number of attached transformations the MessageEnd() signal should be passed
/// \param blocking specifies whether the object should block when processing input
/// \return the number of bytes that remain in the block (i.e., bytes not processed). 0 indicates all
/// bytes were processed.
/// \details Internally, PutMessageEnd() calls Put2() with a modified propagation to
/// ensure all attached transformations finish processing the message.
/// \details propagation count includes this object. Setting propagation to <tt>1</tt> means this
/// object only. Setting propagation to <tt>-1</tt> means unlimited propagation.
size_t PutMessageEnd(const byte *inString, size_t length, int propagation=-1, bool blocking=true)
{return Put2(inString, length, propagation < 0 ? -1 : propagation+1, blocking);}
/// \brief Input multiple bytes for processing
/// \param inString the byte buffer to process
/// \param length the size of the string, in bytes
/// \param messageEnd means how many filters to signal MessageEnd() to, including this one
/// \param blocking specifies whether the object should block when processing input
/// \return the number of bytes that remain in the block (i.e., bytes not processed). 0 indicates all
/// bytes were processed.
/// \details Derived classes must implement Put2().
virtual size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) =0;
/// \brief Input multiple bytes that may be modified by callee.
/// \param inString the byte buffer to process.
/// \param length the size of the string, in bytes.
/// \param messageEnd means how many filters to signal MessageEnd() to, including this one.
/// \param blocking specifies whether the object should block when processing input.
/// \return the number of bytes that remain in the block (i.e., bytes not processed). 0 indicates all
/// bytes were processed.
/// \details Internally, PutModifiable2() calls Put2().
virtual size_t PutModifiable2(byte *inString, size_t length, int messageEnd, bool blocking)
{return Put2(inString, length, messageEnd, blocking);}
/// \brief Exception thrown by objects that have \a not implemented nonblocking input processing
/// \details BlockingInputOnly inherits from NotImplemented
struct BlockingInputOnly : public NotImplemented
{BlockingInputOnly(const std::string &s) : NotImplemented(s + ": Nonblocking input is not implemented by this object.") {}};
//@}
/// \name WAITING
//@{
/// \brief Retrieves the maximum number of waitable objects
unsigned int GetMaxWaitObjectCount() const;
/// \brief Retrieves waitable objects
/// \param container the wait container to receive the references to the objects
/// \param callStack CallStack() object used to select waitable objects
/// \details GetWaitObjects is usually called in one of two ways. First, it can
/// be called like <tt>something.GetWaitObjects(c, CallStack("my func after X", 0));</tt>.
/// Second, if in an outer GetWaitObjects() method that itself takes a callStack
/// parameter, it can be called like
/// <tt>innerThing.GetWaitObjects(c, CallStack("MyClass::GetWaitObjects at X", &callStack));</tt>.
void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack);
//@} // WAITING
/// \name SIGNALS
//@{
/// \brief Initialize or reinitialize this object, without signal propagation
/// \param parameters a set of NameValuePairs to initialize this object
/// \throws NotImplemented
/// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable
/// number of arbitrarily typed arguments. The function avoids the need for multiple constructors providing
/// all possible combintations of configurable parameters.
/// \details IsolatedInitialize() does not call Initialize() on attached transformations. If initialization
/// should be propagated, then use the Initialize() function.
/// \details If a derived class does not override IsolatedInitialize(), then the base class throws
/// NotImplemented.
virtual void IsolatedInitialize(const NameValuePairs ¶meters) {
CRYPTOPP_UNUSED(parameters);
throw NotImplemented("BufferedTransformation: this object can't be reinitialized");
}
/// \brief Flushes data buffered by this object, without signal propagation
/// \param hardFlush indicates whether all data should be flushed
/// \param blocking specifies whether the object should block when processing input
/// \note hardFlush must be used with care
virtual bool IsolatedFlush(bool hardFlush, bool blocking) =0;
/// \brief Marks the end of a series of messages, without signal propagation
/// \param blocking specifies whether the object should block when completing the processing on
/// the current series of messages
virtual bool IsolatedMessageSeriesEnd(bool blocking)
{CRYPTOPP_UNUSED(blocking); return false;}
/// \brief Initialize or reinitialize this object, with signal propagation
/// \param parameters a set of NameValuePairs to initialize or reinitialize this object
/// \param propagation the number of attached transformations the Initialize() signal should be passed
/// \details Initialize() is used to initialize or reinitialize an object using a variable number of
/// arbitrarily typed arguments. The function avoids the need for multiple constructors providing
/// all possible combintations of configurable parameters.
/// \details propagation count includes this object. Setting propagation to <tt>1</tt> means this
/// object only. Setting propagation to <tt>-1</tt> means unlimited propagation.
virtual void Initialize(const NameValuePairs ¶meters=g_nullNameValuePairs, int propagation=-1);
/// \brief Flush buffered input and/or output, with signal propagation
/// \param hardFlush is used to indicate whether all data should be flushed
/// \param propagation the number of attached transformations the Flush() signal should be passed
/// \param blocking specifies whether the object should block when processing input
/// \details propagation count includes this object. Setting propagation to <tt>1</tt> means this
/// object only. Setting propagation to <tt>-1</tt> means unlimited propagation.
/// \note Hard flushes must be used with care. It means try to process and output everything, even if
/// there may not be enough data to complete the action. For example, hard flushing a HexDecoder
/// would cause an error if you do it after inputing an odd number of hex encoded characters.
/// \note For some types of filters, like ZlibDecompressor, hard flushes can only
/// be done at "synchronization points". These synchronization points are positions in the data
/// stream that are created by hard flushes on the corresponding reverse filters, in this
/// example ZlibCompressor. This is useful when zlib compressed data is moved across a
/// network in packets and compression state is preserved across packets, as in the SSH2 protocol.
virtual bool Flush(bool hardFlush, int propagation=-1, bool blocking=true);
/// \brief Marks the end of a series of messages, with signal propagation
/// \param propagation the number of attached transformations the MessageSeriesEnd() signal should be passed
/// \param blocking specifies whether the object should block when processing input
/// \details Each object that receives the signal will perform its processing, decrement
/// propagation, and then pass the signal on to attached transformations if the value is not 0.
/// \details propagation count includes this object. Setting propagation to <tt>1</tt> means this
/// object only. Setting propagation to <tt>-1</tt> means unlimited propagation.
/// \note There should be a MessageEnd() immediately before MessageSeriesEnd().
virtual bool MessageSeriesEnd(int propagation=-1, bool blocking=true);
/// \brief Set propagation of automatically generated and transferred signals
/// \param propagation then new value
/// \details Setting propagation to <tt>0</tt> means do not automatically generate signals. Setting
/// propagation to <tt>-1</tt> means unlimited propagation.
virtual void SetAutoSignalPropagation(int propagation)
{CRYPTOPP_UNUSED(propagation);}
/// \brief Retrieve automatic signal propagation value
/// \return the number of attached transformations the signal is propagated to. 0 indicates
/// the signal is only witnessed by this object
virtual int GetAutoSignalPropagation() const {return 0;}
public:
/// \name RETRIEVAL OF ONE MESSAGE
//@{
/// \brief Provides the number of bytes ready for retrieval
/// \return the number of bytes ready for retrieval
/// \details All retrieval functions return the actual number of bytes retrieved, which is
/// the lesser of the request number and MaxRetrievable()
virtual lword MaxRetrievable() const;
/// \brief Determines whether bytes are ready for retrieval
/// \returns true if bytes are available for retrieval, false otherwise
virtual bool AnyRetrievable() const;
/// \brief Retrieve a 8-bit byte
/// \param outByte the 8-bit value to be retrieved
/// \return the number of bytes consumed during the call.
/// \details Use the return value of Get to detect short reads.
virtual size_t Get(byte &outByte);
/// \brief Retrieve a block of bytes
/// \param outString a block of bytes
/// \param getMax the number of bytes to Get
/// \return the number of bytes consumed during the call.
/// \details Use the return value of Get to detect short reads.
virtual size_t Get(byte *outString, size_t getMax);
/// \brief Peek a 8-bit byte
/// \param outByte the 8-bit value to be retrieved
/// \return the number of bytes read during the call.
/// \details Peek does not remove bytes from the object. Use the return value of
/// Get() to detect short reads.
virtual size_t Peek(byte &outByte) const;
/// \brief Peek a block of bytes
/// \param outString a block of bytes
/// \param peekMax the number of bytes to Peek
/// \return the number of bytes read during the call.
/// \details Peek does not remove bytes from the object. Use the return value of
/// Get() to detect short reads.
virtual size_t Peek(byte *outString, size_t peekMax) const;
/// \brief Retrieve a 16-bit word
/// \param value the 16-bit value to be retrieved
/// \param order the ByteOrder of the value to be processed.
/// \return the number of bytes consumed during the call.
/// \details Use the return value of GetWord16() to detect short reads.
size_t GetWord16(word16 &value, ByteOrder order=BIG_ENDIAN_ORDER);
/// \brief Retrieve a 32-bit word
/// \param value the 32-bit value to be retrieved
/// \param order the ByteOrder of the value to be processed.
/// \return the number of bytes consumed during the call.
/// \details Use the return value of GetWord16() to detect short reads.
size_t GetWord32(word32 &value, ByteOrder order=BIG_ENDIAN_ORDER);
/// \brief Peek a 16-bit word
/// \param value the 16-bit value to be retrieved
/// \param order the ByteOrder of the value to be processed.
/// \return the number of bytes consumed during the call.
/// \details Peek does not consume bytes in the stream. Use the return value
/// of GetWord16() to detect short reads.
size_t PeekWord16(word16 &value, ByteOrder order=BIG_ENDIAN_ORDER) const;
/// \brief Peek a 32-bit word
/// \param value the 32-bit value to be retrieved
/// \param order the ByteOrder of the value to be processed.
/// \return the number of bytes consumed during the call.
/// \details Peek does not consume bytes in the stream. Use the return value
/// of GetWord16() to detect short reads.
size_t PeekWord32(word32 &value, ByteOrder order=BIG_ENDIAN_ORDER) const;
/// move transferMax bytes of the buffered output to target as input
/// \brief Transfer bytes from this object to another BufferedTransformation
/// \param target the destination BufferedTransformation
/// \param transferMax the number of bytes to transfer
/// \param channel the channel on which the transfer should occur
/// \return the number of bytes transferred during the call.
/// \details TransferTo removes bytes from this object and moves them to the destination.
/// \details The function always returns transferMax. If an accurate count is needed, then use TransferTo2().
lword TransferTo(BufferedTransformation &target, lword transferMax=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL)
{TransferTo2(target, transferMax, channel); return transferMax;}
/// \brief Discard skipMax bytes from the output buffer
/// \param skipMax the number of bytes to discard
/// \details Skip() discards bytes from the output buffer, which is the AttachedTransformation(), if present.
/// The function always returns the parameter <tt>skipMax</tt>.
/// \details If you want to skip bytes from a Source, then perform the following.
/// <pre>
/// StringSource ss(str, false, new Redirector(TheBitBucket()));
/// ss.Pump(10); // Skip 10 bytes from Source
/// ss.Detach(new FilterChain(...));
/// ss.PumpAll();
/// </pre>
virtual lword Skip(lword skipMax=LWORD_MAX);
/// copy copyMax bytes of the buffered output to target as input
/// \brief Copy bytes from this object to another BufferedTransformation
/// \param target the destination BufferedTransformation
/// \param copyMax the number of bytes to copy
/// \param channel the channel on which the transfer should occur
/// \return the number of bytes copied during the call.
/// \details CopyTo copies bytes from this object to the destination. The bytes are not removed from this object.
/// \details The function always returns copyMax. If an accurate count is needed, then use CopyRangeTo2().
lword CopyTo(BufferedTransformation &target, lword copyMax=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL) const
{return CopyRangeTo(target, 0, copyMax, channel);}
/// \brief Copy bytes from this object using an index to another BufferedTransformation
/// \param target the destination BufferedTransformation
/// \param position the 0-based index of the byte stream to begin the copying
/// \param copyMax the number of bytes to copy
/// \param channel the channel on which the transfer should occur
/// \return the number of bytes copied during the call.
/// \details CopyTo copies bytes from this object to the destination. The bytes remain in this
/// object. Copying begins at the index position in the current stream, and not from an absolute
/// position in the stream.
/// \details The function returns the new position in the stream after transferring the bytes starting at the index.
lword CopyRangeTo(BufferedTransformation &target, lword position, lword copyMax=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL) const
{lword i = position; CopyRangeTo2(target, i, i+copyMax, channel); return i-position;}
//@}
/// \name RETRIEVAL OF MULTIPLE MESSAGES
//@{
/// \brief Provides the number of bytes ready for retrieval
/// \return the number of bytes ready for retrieval
virtual lword TotalBytesRetrievable() const;
/// \brief Provides the number of meesages processed by this object
/// \return the number of meesages processed by this object
/// \details NumberOfMessages returns number of times MessageEnd() has been
/// received minus messages retrieved or skipped
virtual unsigned int NumberOfMessages() const;
/// \brief Determines if any messages are available for retrieval
/// \returns true if <tt>NumberOfMessages() > 0</tt>, false otherwise
/// \details AnyMessages returns true if <tt>NumberOfMessages() > 0</tt>
virtual bool AnyMessages() const;
/// \brief Start retrieving the next message
/// \return true if a message is ready for retrieval
/// \details GetNextMessage() returns true if a message is ready for retrieval; false
/// if no more messages exist or this message is not completely retrieved.
virtual bool GetNextMessage();
/// \brief Skip a number of meessages
/// \return 0 if the requested number of messages was skipped, non-0 otherwise
/// \details SkipMessages() skips count number of messages. If there is an AttachedTransformation()
/// then SkipMessages() is called on the attached transformation. If there is no attached
/// transformation, then count number of messages are sent to TheBitBucket() using TransferMessagesTo().
virtual unsigned int SkipMessages(unsigned int count=UINT_MAX);
/// \brief Transfer messages from this object to another BufferedTransformation
/// \param target the destination BufferedTransformation
/// \param count the number of messages to transfer
/// \param channel the channel on which the transfer should occur
/// \return the number of bytes that remain in the current transfer block (i.e., bytes not transferred)
/// \details TransferMessagesTo2() removes messages from this object and moves them to the destination.
/// If all bytes are not transferred for a message, then processing stops and the number of remaining
/// bytes is returned. TransferMessagesTo() does not proceed to the next message.
/// \details A return value of 0 indicates all messages were successfully transferred.
unsigned int TransferMessagesTo(BufferedTransformation &target, unsigned int count=UINT_MAX, const std::string &channel=DEFAULT_CHANNEL)
{TransferMessagesTo2(target, count, channel); return count;}
/// \brief Copy messages from this object to another BufferedTransformation
/// \param target the destination BufferedTransformation
/// \param count the number of messages to transfer
/// \param channel the channel on which the transfer should occur
/// \return the number of bytes that remain in the current transfer block (i.e., bytes not transferred)
/// \details CopyMessagesTo copies messages from this object and copies them to the destination.
/// If all bytes are not transferred for a message, then processing stops and the number of remaining
/// bytes is returned. CopyMessagesTo() does not proceed to the next message.
/// \details A return value of 0 indicates all messages were successfully copied.
unsigned int CopyMessagesTo(BufferedTransformation &target, unsigned int count=UINT_MAX, const std::string &channel=DEFAULT_CHANNEL) const;
/// \brief Skip all messages in the series
virtual void SkipAll();
/// \brief Transfer all bytes from this object to another BufferedTransformation
/// \param target the destination BufferedTransformation
/// \param channel the channel on which the transfer should occur
/// \details TransferMessagesTo2() removes messages from this object and moves them to the destination.
/// Internally TransferAllTo() calls TransferAllTo2().
void TransferAllTo(BufferedTransformation &target, const std::string &channel=DEFAULT_CHANNEL)
{TransferAllTo2(target, channel);}
/// \brief Copy messages from this object to another BufferedTransformation
/// \param target the destination BufferedTransformation
/// \param channel the channel on which the transfer should occur
/// \details CopyAllTo copies messages from this object and copies them to the destination.
void CopyAllTo(BufferedTransformation &target, const std::string &channel=DEFAULT_CHANNEL) const;
/// \brief Retrieve the next message in a series
/// \return true if a message was retreved, false otherwise
/// \details Internally, the base class implementation returns false.
virtual bool GetNextMessageSeries() {return false;}
/// \brief Provides the number of messages in a series
/// \return the number of messages in this series
virtual unsigned int NumberOfMessagesInThisSeries() const {return NumberOfMessages();}
/// \brief Provides the number of messages in a series
/// \return the number of messages in this series
virtual unsigned int NumberOfMessageSeries() const {return 0;}
//@}
/// \name NON-BLOCKING TRANSFER OF OUTPUT
//@{
// upon return, byteCount contains number of bytes that have finished being transferred,
// and returns the number of bytes left in the current transfer block
/// \brief Transfer bytes from this object to another BufferedTransformation
/// \param target the destination BufferedTransformation
/// \param byteCount the number of bytes to transfer
/// \param channel the channel on which the transfer should occur
/// \param blocking specifies whether the object should block when processing input
/// \return the number of bytes that remain in the transfer block (i.e., bytes not transferred)
/// \details TransferTo() removes bytes from this object and moves them to the destination.
/// Transfer begins at the index position in the current stream, and not from an absolute
/// position in the stream.
/// \details byteCount is an \a IN and \a OUT parameter. When the call is made,
/// byteCount is the requested size of the transfer. When the call returns, byteCount is
/// the number of bytes that were transferred.
virtual size_t TransferTo2(BufferedTransformation &target, lword &byteCount, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) =0;
// upon return, begin contains the start position of data yet to be finished copying,
// and returns the number of bytes left in the current transfer block
/// \brief Copy bytes from this object to another BufferedTransformation
/// \param target the destination BufferedTransformation
/// \param begin the 0-based index of the first byte to copy in the stream
/// \param end the 0-based index of the last byte to copy in the stream
/// \param channel the channel on which the transfer should occur
/// \param blocking specifies whether the object should block when processing input
/// \return the number of bytes that remain in the copy block (i.e., bytes not copied)
/// \details CopyRangeTo2 copies bytes from this object to the destination. The bytes are not
/// removed from this object. Copying begins at the index position in the current stream, and
/// not from an absolute position in the stream.
/// \details begin is an \a IN and \a OUT parameter. When the call is made, begin is the
/// starting position of the copy. When the call returns, begin is the position of the first
/// byte that was \a not copied (which may be different than end). begin can be used for
/// subsequent calls to CopyRangeTo2().
virtual size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const =0;
// upon return, messageCount contains number of messages that have finished being transferred,
// and returns the number of bytes left in the current transfer block
/// \brief Transfer messages from this object to another BufferedTransformation
/// \param target the destination BufferedTransformation
/// \param messageCount the number of messages to transfer
/// \param channel the channel on which the transfer should occur
/// \param blocking specifies whether the object should block when processing input
/// \return the number of bytes that remain in the current transfer block (i.e., bytes not transferred)
/// \details TransferMessagesTo2() removes messages from this object and moves them to the destination.
/// \details messageCount is an \a IN and \a OUT parameter. When the call is made, messageCount is the
/// the number of messages requested to be transferred. When the call returns, messageCount is the
/// number of messages actually transferred.
size_t TransferMessagesTo2(BufferedTransformation &target, unsigned int &messageCount, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true);
// returns the number of bytes left in the current transfer block
/// \brief Transfer all bytes from this object to another BufferedTransformation
/// \param target the destination BufferedTransformation
/// \param channel the channel on which the transfer should occur
/// \param blocking specifies whether the object should block when processing input
/// \return the number of bytes that remain in the current transfer block (i.e., bytes not transferred)
/// \details TransferMessagesTo2() removes messages from this object and moves them to the destination.
size_t TransferAllTo2(BufferedTransformation &target, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true);
//@}
/// \name CHANNELS
//@{
/// \brief Exception thrown when a filter does not support named channels
struct NoChannelSupport : public NotImplemented
{NoChannelSupport(const std::string &name) : NotImplemented(name + ": this object doesn't support multiple channels") {}};
/// \brief Exception thrown when a filter does not recognize a named channel
struct InvalidChannelName : public InvalidArgument
{InvalidChannelName(const std::string &name, const std::string &channel) : InvalidArgument(name + ": unexpected channel name \"" + channel + "\"") {}};
/// \brief Input a byte for processing on a channel
/// \param channel the channel to process the data.
/// \param inByte the 8-bit byte (octet) to be processed.
/// \param blocking specifies whether the object should block when processing input.
/// \return 0 indicates all bytes were processed during the call. Non-0 indicates the
/// number of bytes that were not processed.
size_t ChannelPut(const std::string &channel, byte inByte, bool blocking=true)
{return ChannelPut(channel, &inByte, 1, blocking);}
/// \brief Input a byte buffer for processing on a channel
/// \param channel the channel to process the data
/// \param inString the byte buffer to process
/// \param length the size of the string, in bytes
/// \param blocking specifies whether the object should block when processing input
/// \return 0 indicates all bytes were processed during the call. Non-0 indicates the
/// number of bytes that were not processed.
size_t ChannelPut(const std::string &channel, const byte *inString, size_t length, bool blocking=true)
{return ChannelPut2(channel, inString, length, 0, blocking);}
/// \brief Input multiple bytes that may be modified by callee on a channel
/// \param channel the channel to process the data.
/// \param inString the byte buffer to process
/// \param length the size of the string, in bytes
/// \param blocking specifies whether the object should block when processing input
/// \return 0 indicates all bytes were processed during the call. Non-0 indicates the
/// number of bytes that were not processed.
size_t ChannelPutModifiable(const std::string &channel, byte *inString, size_t length, bool blocking=true)
{return ChannelPutModifiable2(channel, inString, length, 0, blocking);}
/// \brief Input a 16-bit word for processing on a channel.
/// \param channel the channel to process the data.
/// \param value the 16-bit value to be processed.
/// \param order the ByteOrder of the value to be processed.
/// \param blocking specifies whether the object should block when processing input.
/// \return 0 indicates all bytes were processed during the call. Non-0 indicates the
/// number of bytes that were not processed.
size_t ChannelPutWord16(const std::string &channel, word16 value, ByteOrder order=BIG_ENDIAN_ORDER, bool blocking=true);
/// \brief Input a 32-bit word for processing on a channel.
/// \param channel the channel to process the data.
/// \param value the 32-bit value to be processed.
/// \param order the ByteOrder of the value to be processed.
/// \param blocking specifies whether the object should block when processing input.
/// \return 0 indicates all bytes were processed during the call. Non-0 indicates the
/// number of bytes that were not processed.
size_t ChannelPutWord32(const std::string &channel, word32 value, ByteOrder order=BIG_ENDIAN_ORDER, bool blocking=true);
/// \brief Signal the end of a message
/// \param channel the channel to process the data.
/// \param propagation the number of attached transformations the ChannelMessageEnd() signal should be passed
/// \param blocking specifies whether the object should block when processing input
/// \return 0 indicates all bytes were processed during the call. Non-0 indicates the
/// number of bytes that were not processed.
/// \details propagation count includes this object. Setting propagation to <tt>1</tt> means this
/// object only. Setting propagation to <tt>-1</tt> means unlimited propagation.
bool ChannelMessageEnd(const std::string &channel, int propagation=-1, bool blocking=true)
{return !!ChannelPut2(channel, NULLPTR, 0, propagation < 0 ? -1 : propagation+1, blocking);}
/// \brief Input multiple bytes for processing and signal the end of a message
/// \param channel the channel to process the data.
/// \param inString the byte buffer to process
/// \param length the size of the string, in bytes
/// \param propagation the number of attached transformations the ChannelPutMessageEnd() signal should be passed
/// \param blocking specifies whether the object should block when processing input
/// \return the number of bytes that remain in the block (i.e., bytes not processed)
/// \details propagation count includes this object. Setting propagation to <tt>1</tt> means this
/// object only. Setting propagation to <tt>-1</tt> means unlimited propagation.
size_t ChannelPutMessageEnd(const std::string &channel, const byte *inString, size_t length, int propagation=-1, bool blocking=true)
{return ChannelPut2(channel, inString, length, propagation < 0 ? -1 : propagation+1, blocking);}
/// \brief Request space which can be written into by the caller
/// \param channel the channel to process the data
/// \param size the requested size of the buffer
/// \return a pointer to a memory block with length size
/// \details The purpose of this method is to help avoid extra memory allocations.
/// \details size is an \a IN and \a OUT parameter and used as a hint. When the call is made,
/// size is the requested size of the buffer. When the call returns, size is the size of
/// the array returned to the caller.
/// \details The base class implementation sets size to 0 and returns NULL.
/// \note Some objects, like ArraySink(), cannot create a space because its fixed. In the case of
/// an ArraySink(), the pointer to the array is returned and the size is remaining size.
virtual byte * ChannelCreatePutSpace(const std::string &channel, size_t &size);
/// \brief Input multiple bytes for processing on a channel.
/// \param channel the channel to process the data.
/// \param inString the byte buffer to process.
/// \param length the size of the string, in bytes.
/// \param messageEnd means how many filters to signal MessageEnd() to, including this one.
/// \param blocking specifies whether the object should block when processing input.
/// \return the number of bytes that remain in the block (i.e., bytes not processed)
virtual size_t ChannelPut2(const std::string &channel, const byte *inString, size_t length, int messageEnd, bool blocking);
/// \brief Input multiple bytes that may be modified by callee on a channel
/// \param channel the channel to process the data
/// \param inString the byte buffer to process
/// \param length the size of the string, in bytes
/// \param messageEnd means how many filters to signal MessageEnd() to, including this one
/// \param blocking specifies whether the object should block when processing input
/// \return the number of bytes that remain in the block (i.e., bytes not processed)
virtual size_t ChannelPutModifiable2(const std::string &channel, byte *inString, size_t length, int messageEnd, bool blocking);
/// \brief Flush buffered input and/or output on a channel
/// \param channel the channel to flush the data
/// \param hardFlush is used to indicate whether all data should be flushed
/// \param propagation the number of attached transformations the ChannelFlush() signal should be passed
/// \param blocking specifies whether the object should block when processing input
/// \return true of the Flush was successful
/// \details propagation count includes this object. Setting propagation to <tt>1</tt> means this
/// object only. Setting propagation to <tt>-1</tt> means unlimited propagation.
virtual bool ChannelFlush(const std::string &channel, bool hardFlush, int propagation=-1, bool blocking=true);
/// \brief Marks the end of a series of messages on a channel
/// \param channel the channel to signal the end of a series of messages
/// \param propagation the number of attached transformations the ChannelMessageSeriesEnd() signal should be passed
/// \param blocking specifies whether the object should block when processing input
/// \details Each object that receives the signal will perform its processing, decrement
/// propagation, and then pass the signal on to attached transformations if the value is not 0.
/// \details propagation count includes this object. Setting propagation to <tt>1</tt> means this
/// object only. Setting propagation to <tt>-1</tt> means unlimited propagation.
/// \note There should be a MessageEnd() immediately before MessageSeriesEnd().
virtual bool ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1, bool blocking=true);
/// \brief Sets the default retrieval channel
/// \param channel the channel to signal the end of a series of messages
/// \note this function may not be implemented in all objects that should support it.
virtual void SetRetrievalChannel(const std::string &channel);
//@}
/// \name ATTACHMENT
/// \details Some BufferedTransformation objects (e.g. Filter objects) allow other BufferedTransformation objects to be
/// attached. When this is done, the first object instead of buffering its output, sends that output to the attached
/// object as input. The entire attachment chain is deleted when the anchor object is destructed.
//@{
/// \brief Determines whether the object allows attachment
/// \return true if the object allows an attachment, false otherwise
/// \details Sources and Filters will returns true, while Sinks and other objects will return false.
virtual bool Attachable() {return false;}
/// \brief Returns the object immediately attached to this object
/// \return the attached transformation
/// \details AttachedTransformation() returns NULL if there is no attachment. The non-const
/// version of AttachedTransformation() always returns NULL.
virtual BufferedTransformation *AttachedTransformation() {CRYPTOPP_ASSERT(!Attachable()); return NULLPTR;}
/// \brief Returns the object immediately attached to this object
/// \return the attached transformation
/// \details AttachedTransformation() returns NULL if there is no attachment. The non-const
/// version of AttachedTransformation() always returns NULL.
virtual const BufferedTransformation *AttachedTransformation() const
{return const_cast<BufferedTransformation *>(this)->AttachedTransformation();}
/// \brief Delete the current attachment chain and attach a new one
/// \param newAttachment the new BufferedTransformation to attach
/// \throws NotImplemented
/// \details Detach() deletes the current attachment chain and replace it with an optional newAttachment
/// \details If a derived class does not override Detach(), then the base class throws
/// NotImplemented.
virtual void Detach(BufferedTransformation *newAttachment = NULLPTR) {
CRYPTOPP_UNUSED(newAttachment); CRYPTOPP_ASSERT(!Attachable());
throw NotImplemented("BufferedTransformation: this object is not attachable");
}
/// \brief Add newAttachment to the end of attachment chain
/// \param newAttachment the attachment to add to the end of the chain
virtual void Attach(BufferedTransformation *newAttachment);
//@}
protected: /// \brief Decrements the propagation count while clamping at 0 /// \return the decremented propagation or 0 static int DecrementPropagation(int propagation) {return propagation != 0 ? propagation - 1 : 0;}
private: byte m_buf[4]; // for ChannelPutWord16 and ChannelPutWord32, to ensure buffer isn't deallocated before non-blocking operation completes };
/// \brief An input discarding BufferedTransformation /// \return a reference to a BufferedTransformation object that discards all input CRYPTOPP_DLL BufferedTransformation & TheBitBucket();
/// \brief Interface for crypto material, such as public and private keys, and crypto parameters class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CryptoMaterial : public NameValuePairs { public: /// Exception thrown when invalid crypto material is detected class CRYPTOPP_DLL InvalidMaterial : public InvalidDataFormat { public: explicit InvalidMaterial(const std::string &s) : InvalidDataFormat(s) {} };
virtual ~CryptoMaterial() {}
/// \brief Assign values to this object
/// \details This function can be used to create a public key from a private key.
virtual void AssignFrom(const NameValuePairs &source) =0;
/// \brief Check this object for errors
/// \param rng a RandomNumberGenerator for objects which use randomized testing
/// \param level the level of thoroughness
/// \returns true if the tests succeed, false otherwise
/// \details There are four levels of thoroughness:
/// <ul>
/// <li>0 - using this object won't cause a crash or exception
/// <li>1 - this object will probably function, and encrypt, sign, other operations correctly
/// <li>2 - ensure this object will function correctly, and perform reasonable security checks
/// <li>3 - perform reasonable security checks, and do checks that may take a long time
/// </ul>
/// \details Level 0 does not require a RandomNumberGenerator. A NullRNG() can be used for level 0.
/// Level 1 may not check for weak keys and such. Levels 2 and 3 are recommended.
/// \sa ThrowIfInvalid()
virtual bool Validate(RandomNumberGenerator &rng, unsigned int level) const =0;
/// \brief Check this object for errors
/// \param rng a RandomNumberGenerator for objects which use randomized testing
/// \param level the level of thoroughness
/// \throws InvalidMaterial
/// \details Internally, ThrowIfInvalid() calls Validate() and throws InvalidMaterial() if validation fails.
/// \sa Validate()
virtual void ThrowIfInvalid(RandomNumberGenerator &rng, unsigned int level) const
{if (!Validate(rng, level)) throw InvalidMaterial("CryptoMaterial: this object contains invalid values");}
/// \brief Saves a key to a BufferedTransformation
/// \param bt the destination BufferedTransformation
/// \throws NotImplemented
/// \details Save() writes the material to a BufferedTransformation.
/// \details If the material is a key, then the key is written with ASN.1 DER encoding. The key
/// includes an object identifier with an algorthm id, like a subjectPublicKeyInfo.
/// \details A "raw" key without the "key info" can be saved using a key's DEREncode() method.
/// \details If a derived class does not override Save(), then the base class throws
/// NotImplemented().
virtual void Save(BufferedTransformation &bt) const
{CRYPTOPP_UNUSED(bt); throw NotImplemented("CryptoMaterial: this object does not support saving");}
/// \brief Loads a key from a BufferedTransformation
/// \param bt the source BufferedTransformation
/// \throws KeyingErr
/// \details Load() attempts to read material from a BufferedTransformation. If the
/// material is a key that was generated outside the library, then the following
/// usually applies:
/// <ul>
/// <li>the key should be ASN.1 BER encoded
/// <li>the key should be a "key info"
/// </ul>
/// \details "key info" means the key should have an object identifier with an algorthm id,
/// like a subjectPublicKeyInfo.
/// \details To read a "raw" key without the "key info", then call the key's BERDecode() method.
/// \note Load() generally does not check that the key is valid. Call Validate(), if needed.
virtual void Load(BufferedTransformation &bt)
{CRYPTOPP_UNUSED(bt); throw NotImplemented("CryptoMaterial: this object does not support loading");}
/// \brief Determines whether the object supports precomputation
/// \return true if the object supports precomputation, false otherwise
/// \sa Precompute()
virtual bool SupportsPrecomputation() const {return false;}
/// \brief Perform precomputation
/// \param precomputationStorage the suggested number of objects for the precompute table
/// \throws NotImplemented
/// \details The exact semantics of Precompute() varies, but it typically means calculate
/// a table of n objects that can be used later to speed up computation.
/// \details If a derived class does not override Precompute(), then the base class throws
/// NotImplemented.
/// \sa SupportsPrecomputation(), LoadPrecomputation(), SavePrecomputation()
virtual void Precompute(unsigned int precomputationStorage) {
CRYPTOPP_UNUSED(precomputationStorage); CRYPTOPP_ASSERT(!SupportsPrecomputation());
throw NotImplemented("CryptoMaterial: this object does not support precomputation");
}
/// \brief Retrieve previously saved precomputation
/// \param storedPrecomputation BufferedTransformation with the saved precomputation
/// \throws NotImplemented
/// \sa SupportsPrecomputation(), Precompute()
virtual void LoadPrecomputation(BufferedTransformation &storedPrecomputation)
{CRYPTOPP_UNUSED(storedPrecomputation); CRYPTOPP_ASSERT(!SupportsPrecomputation()); throw NotImplemented("CryptoMaterial: this object does not support precomputation");}
/// \brief Save precomputation for later use
/// \param storedPrecomputation BufferedTransformation to write the precomputation
/// \throws NotImplemented
/// \sa SupportsPrecomputation(), Precompute()
virtual void SavePrecomputation(BufferedTransformation &storedPrecomputation) const
{CRYPTOPP_UNUSED(storedPrecomputation); CRYPTOPP_ASSERT(!SupportsPrecomputation()); throw NotImplemented("CryptoMaterial: this object does not support precomputation");}
/// \brief Perform a quick sanity check
/// \details DoQuickSanityCheck() is for internal library use, and it should not be called by library users.
void DoQuickSanityCheck() const {ThrowIfInvalid(NullRNG(), 0);}
#if defined(__SUNPRO_CC) // Sun Studio 11/CC 5.8 workaround: it generates incorrect code // when casting to an empty virtual base class. JW, 2018: It is // still a problem in Sun Studio 12.6/CC 5.15 on i386. Just enable // it everywhere in case it affects SPARC (which we don't test). char m_sunCCworkaround; #endif };
/// \brief Interface for generatable crypto material, such as private keys and crypto parameters class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE GeneratableCryptoMaterial : virtual public CryptoMaterial { public: virtual ~GeneratableCryptoMaterial() {}
/// \brief Generate a random key or crypto parameters
/// \param rng a RandomNumberGenerator to produce keying material
/// \param params additional initialization parameters
/// \throws KeyingErr if a key can't be generated or algorithm parameters are invalid
/// \details If a derived class does not override GenerateRandom(), then the base class throws
/// NotImplemented.
virtual void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs ¶ms = g_nullNameValuePairs) {
CRYPTOPP_UNUSED(rng); CRYPTOPP_UNUSED(params);
throw NotImplemented("GeneratableCryptoMaterial: this object does not support key/parameter generation");
}
/// \brief Generate a random key or crypto parameters
/// \param rng a RandomNumberGenerator to produce keying material
/// \param keySize the size of the key, in bits
/// \throws KeyingErr if a key can't be generated or algorithm parameters are invalid
/// \details GenerateRandomWithKeySize calls GenerateRandom() with a NameValuePairs
/// object with only "KeySize"
void GenerateRandomWithKeySize(RandomNumberGenerator &rng, unsigned int keySize);
};
/// \brief Interface for public keys class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PublicKey : virtual public CryptoMaterial { };
/// \brief Interface for private keys class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PrivateKey : public GeneratableCryptoMaterial { };
/// \brief Interface for crypto prameters class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CryptoParameters : public GeneratableCryptoMaterial { };
/// \brief Interface for asymmetric algorithms /// \details BERDecode() and DEREncode() were removed under Issue 569 /// and Commit 9b174e84de7a. Programs should use AccessMaterial().Load(bt) /// or AccessMaterial().Save(bt) instead. /// \sa Issue 569 class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE AsymmetricAlgorithm : public Algorithm { public: virtual ~AsymmetricAlgorithm() {}
/// \brief Retrieves a reference to CryptoMaterial
/// \return a reference to the crypto material
virtual CryptoMaterial & AccessMaterial() =0;
/// \brief Retrieves a reference to CryptoMaterial
/// \return a const reference to the crypto material
virtual const CryptoMaterial & GetMaterial() const =0;
#if 0 /// \brief Loads this object from a BufferedTransformation /// \param bt a BufferedTransformation object /// \details Use of BERDecode() changed to Load() at Issue 569. /// \deprecated for backwards compatibility, calls AccessMaterial().Load(bt) void BERDecode(BufferedTransformation &bt) {AccessMaterial().Load(bt);}
/// \brief Saves this object to a BufferedTransformation
/// \param bt a BufferedTransformation object
/// \details Use of DEREncode() changed to Save() at Issue 569.
/// \deprecated for backwards compatibility, calls GetMaterial().Save(bt)
void DEREncode(BufferedTransformation &bt) const
{GetMaterial().Save(bt);}
#endif };
/// \brief Interface for asymmetric algorithms using public keys class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PublicKeyAlgorithm : public AsymmetricAlgorithm { public: virtual ~PublicKeyAlgorithm() {}
// VC60 workaround: no co-variant return type
/// \brief Retrieves a reference to a Public Key
/// \return a reference to the public key
CryptoMaterial & AccessMaterial()
{return AccessPublicKey();}
/// \brief Retrieves a reference to a Public Key
/// \return a const reference the public key
const CryptoMaterial & GetMaterial() const
{return GetPublicKey();}
/// \brief Retrieves a reference to a Public Key
/// \return a reference to the public key
virtual PublicKey & AccessPublicKey() =0;
/// \brief Retrieves a reference to a Public Key
/// \return a const reference the public key
virtual const PublicKey & GetPublicKey() const
{return const_cast<PublicKeyAlgorithm *>(this)->AccessPublicKey();}
};
/// \brief Interface for asymmetric algorithms using private keys class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PrivateKeyAlgorithm : public AsymmetricAlgorithm { public: virtual ~PrivateKeyAlgorithm() {}
/// \brief Retrieves a reference to a Private Key
/// \return a reference the private key
CryptoMaterial & AccessMaterial() {return AccessPrivateKey();}
/// \brief Retrieves a reference to a Private Key
/// \return a const reference the private key
const CryptoMaterial & GetMaterial() const {return GetPrivateKey();}
/// \brief Retrieves a reference to a Private Key
/// \return a reference the private key
virtual PrivateKey & AccessPrivateKey() =0;
/// \brief Retrieves a reference to a Private Key
/// \return a const reference the private key
virtual const PrivateKey & GetPrivateKey() const {return const_cast<PrivateKeyAlgorithm *>(this)->AccessPrivateKey();}
};
/// \brief Interface for key agreement algorithms class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE KeyAgreementAlgorithm : public AsymmetricAlgorithm { public: virtual ~KeyAgreementAlgorithm() {}
/// \brief Retrieves a reference to Crypto Parameters
/// \return a reference the crypto parameters
CryptoMaterial & AccessMaterial() {return AccessCryptoParameters();}
/// \brief Retrieves a reference to Crypto Parameters
/// \return a const reference the crypto parameters
const CryptoMaterial & GetMaterial() const {return GetCryptoParameters();}
/// \brief Retrieves a reference to Crypto Parameters
/// \return a reference the crypto parameters
virtual CryptoParameters & AccessCryptoParameters() =0;
/// \brief Retrieves a reference to Crypto Parameters
/// \return a const reference the crypto parameters
virtual const CryptoParameters & GetCryptoParameters() const {return const_cast<KeyAgreementAlgorithm *>(this)->AccessCryptoParameters();}
};
/// \brief Interface for public-key encryptors and decryptors /// \details This class provides an interface common to encryptors and decryptors /// for querying their plaintext and ciphertext lengths. class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_CryptoSystem { public: virtual ~PK_CryptoSystem() {}
/// \brief Provides the maximum length of plaintext for a given ciphertext length
/// \return the maximum size of the plaintext, in bytes
/// \details This function returns 0 if ciphertextLength is not valid (too long or too short).
virtual size_t MaxPlaintextLength(size_t ciphertextLength) const =0;
/// \brief Calculate the length of ciphertext given length of plaintext
/// \return the maximum size of the ciphertext, in bytes
/// \details This function returns 0 if plaintextLength is not valid (too long).
virtual size_t CiphertextLength(size_t plaintextLength) const =0;
/// \brief Determines whether this object supports the use of a named parameter
/// \param name the name of the parameter
/// \return true if the parameter name is supported, false otherwise
/// \details Some possible parameter names: EncodingParameters(), KeyDerivationParameters()
/// and others Parameters listed in argnames.h
virtual bool ParameterSupported(const char *name) const =0;
/// \brief Provides the fixed ciphertext length, if one exists
/// \return the fixed ciphertext length if one exists, otherwise 0
/// \details "Fixed" here means length of ciphertext does not depend on length of plaintext.
/// In this case, it usually does depend on the key length.
virtual size_t FixedCiphertextLength() const {return 0;}
/// \brief Provides the maximum plaintext length given a fixed ciphertext length
/// \return maximum plaintext length given the fixed ciphertext length, if one exists,
/// otherwise return 0.
/// \details FixedMaxPlaintextLength(0 returns the maximum plaintext length given the fixed ciphertext
/// length, if one exists, otherwise return 0.
virtual size_t FixedMaxPlaintextLength() const {return 0;}
};
/// \brief Interface for public-key encryptors class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_Encryptor : public PK_CryptoSystem, public PublicKeyAlgorithm { public: /// \brief Exception thrown when trying to encrypt plaintext of invalid length class CRYPTOPP_DLL InvalidPlaintextLength : public Exception { public: InvalidPlaintextLength() : Exception(OTHER_ERROR, "PK_Encryptor: invalid plaintext length") {} };
/// \brief Encrypt a byte string
/// \param rng a RandomNumberGenerator derived class
/// \param plaintext the plaintext byte buffer
/// \param plaintextLength the size of the plaintext byte buffer
/// \param ciphertext a byte buffer to hold the encrypted string
/// \param parameters a set of NameValuePairs to initialize this object
/// \pre <tt>CiphertextLength(plaintextLength) != 0</tt> ensures the plaintext isn't too large
/// \pre <tt>COUNTOF(ciphertext) == CiphertextLength(plaintextLength)</tt> ensures the output
/// byte buffer is large enough.
/// \sa PK_Decryptor
virtual void Encrypt(RandomNumberGenerator &rng,
const byte *plaintext, size_t plaintextLength,
byte *ciphertext, const NameValuePairs ¶meters = g_nullNameValuePairs) const =0;
/// \brief Create a new encryption filter
/// \param rng a RandomNumberGenerator derived class
/// \param attachment an attached transformation
/// \param parameters a set of NameValuePairs to initialize this object
/// \details \p attachment can be \p NULL. The caller is responsible for deleting the returned pointer.
/// Encoding parameters should be passed in the "EP" channel.
virtual BufferedTransformation * CreateEncryptionFilter(RandomNumberGenerator &rng,
BufferedTransformation *attachment=NULLPTR, const NameValuePairs ¶meters = g_nullNameValuePairs) const;
};
/// \brief Interface for public-key decryptors class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_Decryptor : public PK_CryptoSystem, public PrivateKeyAlgorithm { public: virtual ~PK_Decryptor() {}
/// \brief Decrypt a byte string
/// \param rng a RandomNumberGenerator derived class
/// \param ciphertext the encrypted byte buffer
/// \param ciphertextLength the size of the encrypted byte buffer
/// \param plaintext a byte buffer to hold the decrypted string
/// \param parameters a set of NameValuePairs to initialize this object
/// \return the result of the decryption operation
/// \details If DecodingResult::isValidCoding is true, then DecodingResult::messageLength
/// is valid and holds the the actual length of the plaintext recovered. The result is undefined
/// if decryption failed. If DecodingResult::isValidCoding is false, then DecodingResult::messageLength
/// is undefined.
/// \pre <tt>COUNTOF(plaintext) == MaxPlaintextLength(ciphertextLength)</tt> ensures the output
/// byte buffer is large enough
/// \sa PK_Encryptor
virtual DecodingResult Decrypt(RandomNumberGenerator &rng,
const byte *ciphertext, size_t ciphertextLength,
byte *plaintext, const NameValuePairs ¶meters = g_nullNameValuePairs) const =0;
/// \brief Create a new decryption filter
/// \param rng a RandomNumberGenerator derived class
/// \param attachment an attached transformation
/// \param parameters a set of NameValuePairs to initialize this object
/// \return the newly created decryption filter
/// \note the caller is responsible for deleting the returned pointer
virtual BufferedTransformation * CreateDecryptionFilter(RandomNumberGenerator &rng,
BufferedTransformation *attachment=NULLPTR, const NameValuePairs ¶meters = g_nullNameValuePairs) const;
/// \brief Decrypt a fixed size ciphertext
/// \param rng a RandomNumberGenerator derived class
/// \param ciphertext the encrypted byte buffer
/// \param plaintext a byte buffer to hold the decrypted string
/// \param parameters a set of NameValuePairs to initialize this object
/// \return the result of the decryption operation
/// \details If DecodingResult::isValidCoding is true, then DecodingResult::messageLength
/// is valid and holds the the actual length of the plaintext recovered. The result is undefined
/// if decryption failed. If DecodingResult::isValidCoding is false, then DecodingResult::messageLength
/// is undefined.
/// \pre <tt>COUNTOF(plaintext) == MaxPlaintextLength(ciphertextLength)</tt> ensures the output
/// byte buffer is large enough
/// \sa PK_Encryptor
DecodingResult FixedLengthDecrypt(RandomNumberGenerator &rng, const byte *ciphertext, byte *plaintext, const NameValuePairs ¶meters = g_nullNameValuePairs) const
{return Decrypt(rng, ciphertext, FixedCiphertextLength(), plaintext, parameters);}
};
/// \brief Interface for public-key signers and verifiers /// \details This class provides an interface common to signers and verifiers for querying scheme properties /// \sa DL_SignatureSchemeBase, TF_SignatureSchemeBase, DL_SignerBase, TF_SignerBase class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_SignatureScheme { public: /// \brief Exception throw when the private or public key has a length that can't be used /// \details InvalidKeyLength() may be thrown by any function in this class if the private /// or public key has a length that can't be used class CRYPTOPP_DLL InvalidKeyLength : public Exception { public: InvalidKeyLength(const std::string &message) : Exception(OTHER_ERROR, message) {} };
/// \brief Exception throw when the private or public key is too short to sign or verify
/// \details KeyTooShort() may be thrown by any function in this class if the private or public
/// key is too short to sign or verify anything
class CRYPTOPP_DLL KeyTooShort : public InvalidKeyLength
{
public:
KeyTooShort() : InvalidKeyLength("PK_Signer: key too short for this signature scheme") {}
};
virtual ~PK_SignatureScheme() {}
/// \brief Provides the signature length if it only depends on the key
/// \return the signature length if it only depends on the key, in bytes
/// \details SignatureLength() returns the signature length if it only depends on the key, otherwise 0.
virtual size_t SignatureLength() const =0;
/// \brief Provides the maximum signature length produced given the length of the recoverable message part
/// \param recoverablePartLength the length of the recoverable message part, in bytes
/// \return the maximum signature length produced for a given length of recoverable message part, in bytes
/// \details MaxSignatureLength() returns the maximum signature length produced given the length of the
/// recoverable message part.
virtual size_t MaxSignatureLength(size_t recoverablePartLength = 0) const
{CRYPTOPP_UNUSED(recoverablePartLength); return SignatureLength();}
/// \brief Provides the length of longest message that can be recovered
/// \return the length of longest message that can be recovered, in bytes
/// \details MaxRecoverableLength() returns the length of longest message that can be recovered, or 0 if
/// this signature scheme does not support message recovery.
virtual size_t MaxRecoverableLength() const =0;
/// \brief Provides the length of longest message that can be recovered from a signature of given length
/// \param signatureLength the length of the signature, in bytes
/// \return the length of longest message that can be recovered from a signature of given length, in bytes
/// \details MaxRecoverableLengthFromSignatureLength() returns the length of longest message that can be
/// recovered from a signature of given length, or 0 if this signature scheme does not support message
/// recovery.
virtual size_t MaxRecoverableLengthFromSignatureLength(size_t signatureLength) const =0;
/// \brief Determines whether a signature scheme requires a random number generator
/// \return true if the signature scheme requires a RandomNumberGenerator() to sign
/// \details if IsProbabilistic() returns false, then NullRNG() can be passed to functions that take
/// RandomNumberGenerator().
virtual bool IsProbabilistic() const =0;
/// \brief Determines whether the non-recoverable message part can be signed
/// \return true if the non-recoverable message part can be signed
virtual bool AllowNonrecoverablePart() const =0;
/// \brief Determines whether the signature must be input before the message
/// \return true if the signature must be input before the message during verifcation
/// \details if SignatureUpfront() returns true, then you must input the signature before the message
/// during verification. Otherwise you can input the signature at anytime.
virtual bool SignatureUpfront() const {return false;}
/// \brief Determines whether the recoverable part must be input before the non-recoverable part
/// \return true if the recoverable part must be input before the non-recoverable part during signing
/// \details RecoverablePartFirst() determines whether you must input the recoverable part before the
/// non-recoverable part during signing
virtual bool RecoverablePartFirst() const =0;
};
/// \brief Interface for accumulating messages to be signed or verified /// \details Only Update() should be called from the PK_MessageAccumulator() class. No other functions /// inherited from HashTransformation, like DigestSize() and TruncatedFinal(), should be called. class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_MessageAccumulator : public HashTransformation { public: /// \warning DigestSize() should not be called on PK_MessageAccumulator unsigned int DigestSize() const {throw NotImplemented("PK_MessageAccumulator: DigestSize() should not be called");}
/// \warning TruncatedFinal() should not be called on PK_MessageAccumulator
void TruncatedFinal(byte *digest, size_t digestSize)
{
CRYPTOPP_UNUSED(digest); CRYPTOPP_UNUSED(digestSize);
throw NotImplemented("PK_MessageAccumulator: TruncatedFinal() should not be called");
}
};
/// \brief Interface for public-key signers class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_Signer : public PK_SignatureScheme, public PrivateKeyAlgorithm { public: virtual ~PK_Signer() {}
/// \brief Create a new HashTransformation to accumulate the message to be signed
/// \param rng a RandomNumberGenerator derived class
/// \return a pointer to a PK_MessageAccumulator
/// \details NewSignatureAccumulator() can be used with all signing methods. Sign() will autimatically delete the
/// accumulator pointer. The caller is responsible for deletion if a method is called that takes a reference.
virtual PK_MessageAccumulator * NewSignatureAccumulator(RandomNumberGenerator &rng) const =0;
/// \brief Input a recoverable message to an accumulator
/// \param messageAccumulator a reference to a PK_MessageAccumulator
/// \param recoverableMessage a pointer to the recoverable message part to be signed
/// \param recoverableMessageLength the size of the recoverable message part
virtual void InputRecoverableMessage(PK_MessageAccumulator &messageAccumulator, const byte *recoverableMessage, size_t recoverableMessageLength) const =0;
/// \brief Sign and delete the messageAccumulator
/// \param rng a RandomNumberGenerator derived class
/// \param messageAccumulator a pointer to a PK_MessageAccumulator derived class
/// \param signature a block of bytes for the signature
/// \return actual signature length
/// \details Sign() deletes the messageAccumulator, even if an exception is thrown.
/// \pre <tt>COUNTOF(signature) == MaxSignatureLength()</tt>
virtual size_t Sign(RandomNumberGenerator &rng, PK_MessageAccumulator *messageAccumulator, byte *signature) const;
/// \brief Sign and restart messageAccumulator
/// \param rng a RandomNumberGenerator derived class
/// \param messageAccumulator a pointer to a PK_MessageAccumulator derived class
/// \param signature a block of bytes for the signature
/// \param restart flag indicating whether the messageAccumulator should be restarted
/// \return actual signature length
/// \pre <tt>COUNTOF(signature) == MaxSignatureLength()</tt>
virtual size_t SignAndRestart(RandomNumberGenerator &rng, PK_MessageAccumulator &messageAccumulator, byte *signature, bool restart=true) const =0;
/// \brief Sign a message
/// \param rng a RandomNumberGenerator derived class
/// \param message a pointer to the message
/// \param messageLen the size of the message to be signed
/// \param signature a block of bytes for the signature
/// \return actual signature length
/// \pre <tt>COUNTOF(signature) == MaxSignatureLength()</tt>
virtual size_t SignMessage(RandomNumberGenerator &rng, const byte *message, size_t messageLen, byte *signature) const;
/// \brief Sign a recoverable message
/// \param rng a RandomNumberGenerator derived class
/// \param recoverableMessage a pointer to the recoverable message part to be signed
/// \param recoverableMessageLength the size of the recoverable message part
/// \param nonrecoverableMessage a pointer to the non-recoverable message part to be signed
/// \param nonrecoverableMessageLength the size of the non-recoverable message part
/// \param signature a block of bytes for the signature
/// \return actual signature length
/// \pre <tt>COUNTOF(signature) == MaxSignatureLength(recoverableMessageLength)</tt>
virtual size_t SignMessageWithRecovery(RandomNumberGenerator &rng, const byte *recoverableMessage, size_t recoverableMessageLength,
const byte *nonrecoverableMessage, size_t nonrecoverableMessageLength, byte *signature) const;
};
/// \brief Interface for public-key signature verifiers /// \details The Recover* functions throw NotImplemented if the signature scheme does not support /// message recovery. /// \details The Verify* functions throw InvalidDataFormat if the scheme does support message /// recovery and the signature contains a non-empty recoverable message part. The /// Recover* functions should be used in that case. class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_Verifier : public PK_SignatureScheme, public PublicKeyAlgorithm { public: virtual ~PK_Verifier() {}
/// \brief Create a new HashTransformation to accumulate the message to be verified
/// \return a pointer to a PK_MessageAccumulator
/// \details NewVerificationAccumulator() can be used with all verification methods. Verify() will autimatically delete
/// the accumulator pointer. The caller is responsible for deletion if a method is called that takes a reference.
virtual PK_MessageAccumulator * NewVerificationAccumulator() const =0;
/// \brief Input signature into a message accumulator
/// \param messageAccumulator a pointer to a PK_MessageAccumulator derived class
/// \param signature the signature on the message
/// \param signatureLength the size of the signature
virtual void InputSignature(PK_MessageAccumulator &messageAccumulator, const byte *signature, size_t signatureLength) const =0;
/// \brief Check whether messageAccumulator contains a valid signature and message
/// \param messageAccumulator a pointer to a PK_MessageAccumulator derived class
/// \return true if the signature is valid, false otherwise
/// \details Verify() deletes the messageAccumulator, even if an exception is thrown.
virtual bool Verify(PK_MessageAccumulator *messageAccumulator) const;
/// \brief Check whether messageAccumulator contains a valid signature and message, and restart messageAccumulator
/// \param messageAccumulator a reference to a PK_MessageAccumulator derived class
/// \return true if the signature is valid, false otherwise
/// \details VerifyAndRestart() restarts the messageAccumulator
virtual bool VerifyAndRestart(PK_MessageAccumulator &messageAccumulator) const =0;
/// \brief Check whether input signature is a valid signature for input message
/// \param message a pointer to the message to be verified
/// \param messageLen the size of the message
/// \param signature a pointer to the signature over the message
/// \param signatureLen the size of the signature
/// \return true if the signature is valid, false otherwise
virtual bool VerifyMessage(const byte *message, size_t messageLen,
const byte *signature, size_t signatureLen) const;
/// \brief Recover a message from its signature
/// \param recoveredMessage a pointer to the recoverable message part to be verified
/// \param messageAccumulator a pointer to a PK_MessageAccumulator derived class
/// \return the result of the verification operation
/// \details Recover() deletes the messageAccumulator, even if an exception is thrown.
/// \pre <tt>COUNTOF(recoveredMessage) == MaxRecoverableLengthFromSignatureLength(signatureLength)</tt>
virtual DecodingResult Recover(byte *recoveredMessage, PK_MessageAccumulator *messageAccumulator) const;
/// \brief Recover a message from its signature
/// \param recoveredMessage a pointer to the recoverable message part to be verified
/// \param messageAccumulator a pointer to a PK_MessageAccumulator derived class
/// \return the result of the verification operation
/// \details RecoverAndRestart() restarts the messageAccumulator
/// \pre <tt>COUNTOF(recoveredMessage) == MaxRecoverableLengthFromSignatureLength(signatureLength)</tt>
virtual DecodingResult RecoverAndRestart(byte *recoveredMessage, PK_MessageAccumulator &messageAccumulator) const =0;
/// \brief Recover a message from its signature
/// \param recoveredMessage a pointer for the recovered message
/// \param nonrecoverableMessage a pointer to the non-recoverable message part to be signed
/// \param nonrecoverableMessageLength the size of the non-recoverable message part
/// \param signature the signature on the message
/// \param signatureLength the size of the signature
/// \return the result of the verification operation
/// \pre <tt>COUNTOF(recoveredMessage) == MaxRecoverableLengthFromSignatureLength(signatureLength)</tt>
virtual DecodingResult RecoverMessage(byte *recoveredMessage,
const byte *nonrecoverableMessage, size_t nonrecoverableMessageLength,
const byte *signature, size_t signatureLength) const;
};
/// \brief Interface for domains of simple key agreement protocols /// \details A key agreement domain is a set of parameters that must be shared /// by two parties in a key agreement protocol, along with the algorithms /// for generating key pairs and deriving agreed values. /// \since Crypto++ 3.0 class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE SimpleKeyAgreementDomain : public KeyAgreementAlgorithm { public: virtual ~SimpleKeyAgreementDomain() {}
/// \brief Provides the size of the agreed value
/// \return size of agreed value produced in this domain
virtual unsigned int AgreedValueLength() const =0;
/// \brief Provides the size of the private key
/// \return size of private keys in this domain
virtual unsigned int PrivateKeyLength() const =0;
/// \brief Provides the size of the public key
/// \return size of public keys in this domain
virtual unsigned int PublicKeyLength() const =0;
/// \brief Generate private key in this domain
/// \param rng a RandomNumberGenerator derived class
/// \param privateKey a byte buffer for the generated private key in this domain
/// \pre <tt>COUNTOF(privateKey) == PrivateKeyLength()</tt>
virtual void GeneratePrivateKey(RandomNumberGenerator &rng, byte *privateKey) const =0;
/// \brief Generate a public key from a private key in this domain
/// \param rng a RandomNumberGenerator derived class
/// \param privateKey a byte buffer with the previously generated private key
/// \param publicKey a byte buffer for the generated public key in this domain
/// \pre <tt>COUNTOF(publicKey) == PublicKeyLength()</tt>
virtual void GeneratePublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const =0;
/// \brief Generate a private/public key pair
/// \param rng a RandomNumberGenerator derived class
/// \param privateKey a byte buffer for the generated private key in this domain
/// \param publicKey a byte buffer for the generated public key in this domain
/// \details GenerateKeyPair() is equivalent to calling GeneratePrivateKey() and then GeneratePublicKey().
/// \pre <tt>COUNTOF(privateKey) == PrivateKeyLength()</tt>
/// \pre <tt>COUNTOF(publicKey) == PublicKeyLength()</tt>
virtual void GenerateKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const;
/// \brief Derive agreed value
/// \param agreedValue a byte buffer for the shared secret
/// \param privateKey a byte buffer with your private key in this domain
/// \param otherPublicKey a byte buffer with the other party's public key in this domain
/// \param validateOtherPublicKey a flag indicating if the other party's public key should be validated
/// \return true upon success, false in case of failure
/// \details Agree() derives an agreed value from your private keys and couterparty's public keys.
/// \details The other party's public key is validated by default. If you have previously validated the
/// static public key, use <tt>validateStaticOtherPublicKey=false</tt> to save time.
/// \pre <tt>COUNTOF(agreedValue) == AgreedValueLength()</tt>
/// \pre <tt>COUNTOF(privateKey) == PrivateKeyLength()</tt>
/// \pre <tt>COUNTOF(otherPublicKey) == PublicKeyLength()</tt>
virtual bool Agree(byte *agreedValue, const byte *privateKey, const byte *otherPublicKey, bool validateOtherPublicKey=true) const =0;
};
/// \brief Interface for domains of authenticated key agreement protocols /// \details In an authenticated key agreement protocol, each party has two /// key pairs. The long-lived key pair is called the static key pair, /// and the short-lived key pair is called the ephemeral key pair. /// \since Crypto++ 3.0 class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE AuthenticatedKeyAgreementDomain : public KeyAgreementAlgorithm { public: virtual ~AuthenticatedKeyAgreementDomain() {}
/// \brief Provides the size of the agreed value
/// \return size of agreed value produced in this domain
virtual unsigned int AgreedValueLength() const =0;
/// \brief Provides the size of the static private key
/// \return size of static private keys in this domain
virtual unsigned int StaticPrivateKeyLength() const =0;
/// \brief Provides the size of the static public key
/// \return size of static public keys in this domain
virtual unsigned int StaticPublicKeyLength() const =0;
/// \brief Generate static private key in this domain
/// \param rng a RandomNumberGenerator derived class
/// \param privateKey a byte buffer for the generated private key in this domain
/// \pre <tt>COUNTOF(privateKey) == PrivateStaticKeyLength()</tt>
virtual void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const =0;
/// \brief Generate a static public key from a private key in this domain
/// \param rng a RandomNumberGenerator derived class
/// \param privateKey a byte buffer with the previously generated private key
/// \param publicKey a byte buffer for the generated public key in this domain
/// \pre <tt>COUNTOF(publicKey) == PublicStaticKeyLength()</tt>
virtual void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const =0;
/// \brief Generate a static private/public key pair
/// \param rng a RandomNumberGenerator derived class
/// \param privateKey a byte buffer for the generated private key in this domain
/// \param publicKey a byte buffer for the generated public key in this domain
/// \details GenerateStaticKeyPair() is equivalent to calling GenerateStaticPrivateKey() and then GenerateStaticPublicKey().
/// \pre <tt>COUNTOF(privateKey) == PrivateStaticKeyLength()</tt>
/// \pre <tt>COUNTOF(publicKey) == PublicStaticKeyLength()</tt>
virtual void GenerateStaticKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const;
/// \brief Provides the size of ephemeral private key
/// \return the size of ephemeral private key in this domain
virtual unsigned int EphemeralPrivateKeyLength() const =0;
/// \brief Provides the size of ephemeral public key
/// \return the size of ephemeral public key in this domain
virtual unsigned int EphemeralPublicKeyLength() const =0;
/// \brief Generate ephemeral private key
/// \param rng a RandomNumberGenerator derived class
/// \param privateKey a byte buffer for the generated private key in this domain
/// \pre <tt>COUNTOF(privateKey) == PrivateEphemeralKeyLength()</tt>
virtual void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const =0;
/// \brief Generate ephemeral public key
/// \param rng a RandomNumberGenerator derived class
/// \param privateKey a byte buffer for the generated private key in this domain
/// \param publicKey a byte buffer for the generated public key in this domain
/// \pre <tt>COUNTOF(publicKey) == PublicEphemeralKeyLength()</tt>
virtual void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const =0;
/// \brief Generate private/public key pair
/// \param rng a RandomNumberGenerator derived class
/// \param privateKey a byte buffer for the generated private key in this domain
/// \param publicKey a byte buffer for the generated public key in this domain
/// \details GenerateEphemeralKeyPair() is equivalent to calling GenerateEphemeralPrivateKey() and then GenerateEphemeralPublicKey()
virtual void GenerateEphemeralKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const;
/// \brief Derive agreed value
/// \param agreedValue a byte buffer for the shared secret
/// \param staticPrivateKey a byte buffer with your static private key in this domain
/// \param ephemeralPrivateKey a byte buffer with your ephemeral private key in this domain
/// \param staticOtherPublicKey a byte buffer with the other party's static public key in this domain
/// \param ephemeralOtherPublicKey a byte buffer with the other party's ephemeral public key in this domain
/// \param validateStaticOtherPublicKey a flag indicating if the other party's public key should be validated
/// \return true upon success, false in case of failure
/// \details Agree() derives an agreed value from your private keys and couterparty's public keys.
/// \details The other party's ephemeral public key is validated by default. If you have previously validated
/// the static public key, use <tt>validateStaticOtherPublicKey=false</tt> to save time.
/// \pre <tt>COUNTOF(agreedValue) == AgreedValueLength()</tt>
/// \pre <tt>COUNTOF(staticPrivateKey) == StaticPrivateKeyLength()</tt>
/// \pre <tt>COUNTOF(ephemeralPrivateKey) == EphemeralPrivateKeyLength()</tt>
/// \pre <tt>COUNTOF(staticOtherPublicKey) == StaticPublicKeyLength()</tt>
/// \pre <tt>COUNTOF(ephemeralOtherPublicKey) == EphemeralPublicKeyLength()</tt>
virtual bool Agree(byte *agreedValue,
const byte *staticPrivateKey, const byte *ephemeralPrivateKey,
const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey,
bool validateStaticOtherPublicKey=true) const =0;
};
// interface for password authenticated key agreement protocols, not implemented yet #if 0 /// \brief Interface for protocol sessions /*! The methods should be called in the following order:
InitializeSession(rng, parameters); // or call initialize method in derived class
while (true)
{
if (OutgoingMessageAvailable())
{
length = GetOutgoingMessageLength();
GetOutgoingMessage(message);
; // send outgoing message
}
if (LastMessageProcessed())
break;
; // receive incoming message
ProcessIncomingMessage(message);
}
; // call methods in derived class to obtain result of protocol session
*/ class ProtocolSession { public: /// Exception thrown when an invalid protocol message is processed class ProtocolError : public Exception { public: ProtocolError(ErrorType errorType, const std::string &s) : Exception(errorType, s) {} };
/// Exception thrown when a function is called unexpectedly
/*! for example calling ProcessIncomingMessage() when ProcessedLastMessage() == true */
class UnexpectedMethodCall : public Exception
{
public:
UnexpectedMethodCall(const std::string &s) : Exception(OTHER_ERROR, s) {}
};
virtual ~ProtocolSession() {}
ProtocolSession() : m_rng(NULLPTR), m_throwOnProtocolError(true), m_validState(false) {}
virtual void InitializeSession(RandomNumberGenerator &rng, const NameValuePairs ¶meters) =0;
bool GetThrowOnProtocolError() const {return m_throwOnProtocolError;}
void SetThrowOnProtocolError(bool throwOnProtocolError) {m_throwOnProtocolError = throwOnProtocolError;}
bool HasValidState() const {return m_validState;}
virtual bool OutgoingMessageAvailable() const =0;
virtual unsigned int GetOutgoingMessageLength() const =0;
virtual void GetOutgoingMessage(byte *message) =0;
virtual bool LastMessageProcessed() const =0;
virtual void ProcessIncomingMessage(const byte *message, unsigned int messageLength) =0;
protected: void HandleProtocolError(Exception::ErrorType errorType, const std::string &s) const; void CheckAndHandleInvalidState() const; void SetValidState(bool valid) {m_validState = valid;}
RandomNumberGenerator *m_rng;
private: bool m_throwOnProtocolError, m_validState; };
class KeyAgreementSession : public ProtocolSession { public: virtual ~KeyAgreementSession() {}
virtual unsigned int GetAgreedValueLength() const =0;
virtual void GetAgreedValue(byte *agreedValue) const =0;
};
class PasswordAuthenticatedKeyAgreementSession : public KeyAgreementSession { public: virtual ~PasswordAuthenticatedKeyAgreementSession() {}
void InitializePasswordAuthenticatedKeyAgreementSession(RandomNumberGenerator &rng,
const byte *myId, unsigned int myIdLength,
const byte *counterPartyId, unsigned int counterPartyIdLength,
const byte *passwordOrVerifier, unsigned int passwordOrVerifierLength);
};
/// \brief Password based key agreement domain /// \since Crypto++ 3.0 class PasswordAuthenticatedKeyAgreementDomain : public KeyAgreementAlgorithm { public: virtual ~PasswordAuthenticatedKeyAgreementDomain() {}
/// return whether the domain parameters stored in this object are valid
virtual bool ValidateDomainParameters(RandomNumberGenerator &rng) const
{return GetCryptoParameters().Validate(rng, 2);}
virtual unsigned int GetPasswordVerifierLength(const byte *password, unsigned int passwordLength) const =0;
virtual void GeneratePasswordVerifier(RandomNumberGenerator &rng, const byte *userId, unsigned int userIdLength, const byte *password, unsigned int passwordLength, byte *verifier) const =0;
enum RoleFlags {CLIENT=1, SERVER=2, INITIATOR=4, RESPONDER=8};
virtual bool IsValidRole(unsigned int role) =0;
virtual PasswordAuthenticatedKeyAgreementSession * CreateProtocolSession(unsigned int role) const =0;
}; #endif
/// \brief Exception thrown when an ASN.1 BER decoing error is encountered class CRYPTOPP_DLL BERDecodeErr : public InvalidArgument { public: BERDecodeErr() : InvalidArgument("BER decode error") {} BERDecodeErr(const std::string &s) : InvalidArgument(s) {} };
/// \brief Interface for encoding and decoding ASN1 objects /// \details Each class that derives from ASN1Object should provide a serialization format /// that controls subobject layout. Most of the time the serialization format is /// taken from a standard, like P1363 or an RFC. class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE ASN1Object { public: virtual ~ASN1Object() {}
/// \brief Decode this object from a BufferedTransformation
/// \param bt BufferedTransformation object
/// \details Uses Basic Encoding Rules (BER)
virtual void BERDecode(BufferedTransformation &bt) =0;
/// \brief Encode this object into a BufferedTransformation
/// \param bt BufferedTransformation object
/// \details Uses Distinguished Encoding Rules (DER)
virtual void DEREncode(BufferedTransformation &bt) const =0;
/// \brief Encode this object into a BufferedTransformation
/// \param bt BufferedTransformation object
/// \details Uses Basic Encoding Rules (BER).
/// \details This may be useful if DEREncode() would be too inefficient.
virtual void BEREncode(BufferedTransformation &bt) const {DEREncode(bt);}
};
/// \brief Specifies the build-time version of the library /// \returns integer representing the build-time version /// \details LibraryVersion can help detect inadvertent mixing and matching of library /// versions. When using Crypto++ distributed by a third party, LibraryVersion() /// records the version of the shared object that was built by the third party. /// The LibraryVersion() record resides in cryptlib.o on Unix compatibles /// and cryptlib.obj on Windows. It does not change when an app links /// to the library. /// \details LibraryVersion() is declared with C linkage (extern "C") within the /// CryptoPP namespace to help programs locate the symbol. If the symbol is present, then /// the library version is 5.7 or above. If it is missing, then the library version is /// 5.6.5 or below. /// \details The function could be used as shown below. ///
/// if (LibraryVersion() != HeaderVersion()) /// { /// cout << "Potential version mismatch" << endl; /// /// const int lmaj = (LibraryVersion() / 100U) % 10; /// const int lmin = (LibraryVersion() / 10U) % 10; /// const int hmaj = (HeaderVersion() / 100U) % 10; /// const int hmin = (HeaderVersion() / 10U) % 10; /// /// if(lmaj != hmaj) /// cout << "Major version mismatch" << endl; /// else if(lmin != hmin) /// cout << "Minor version mismatch" << endl; /// } ////// \sa HeaderVersion(), GitHub Issue 371. /// \since Crypto++ 6.0 extern "C" { int LibraryVersion(CRYPTOPP_NOINLINE_DOTDOTDOT); } // C linkage
/// \brief Specifies the runtime version of the library /// \returns integer representing the runtime version /// \details HeaderVersion() can help detect inadvertent mixing and matching of library /// versions. When using Crypto++ distributed by a third party, HeaderVersion() /// records the version of the headers used by the app when the app is compiled. /// \details HeaderVersion() is declared with C linkage (extern "C") within the /// CryptoPP namespace to help programs locate the symbol. If the symbol is present, then /// the library version is 5.7 or above. If it is missing, then the library version is /// 5.6.5 or below. /// \details The function could be used as shown below. ///
/// if (LibraryVersion() != HeaderVersion()) /// { /// cout << "Potential version mismatch" << endl; /// /// const int lmaj = (LibraryVersion() / 100U) % 10; /// const int lmin = (LibraryVersion() / 10U) % 10; /// const int hmaj = (HeaderVersion() / 100U) % 10; /// const int hmin = (HeaderVersion() / 10U) % 10; /// /// if(lmaj != hmaj) /// cout << "Major version mismatch" << endl; /// else if(lmin != hmin) /// cout << "Minor version mismatch" << endl; /// } ////// \sa LibraryVersion(), GitHub Issue 371. /// \since Crypto++ 6.0 extern "C" { inline int HeaderVersion() { return CRYPTOPP_VERSION; } } // C linkage
NAMESPACE_END
#if CRYPTOPP_MSC_VERSION
#endif
#endif
//files.h======================================================================
// files.h - originally written and placed in the public domain by Wei Dai
/// \file files.h /// \brief Classes providing file-based library services /// \since Crypto++ 1.0
#ifndef CRYPTOPP_FILES_H #define CRYPTOPP_FILES_H
#include "cryptlib.h" #include "filters.h" #include "argnames.h" #include "smartptr.h"
#include #include
NAMESPACE_BEGIN(CryptoPP)
/// \brief Implementation of Store interface /// \details file-based implementation of Store interface class CRYPTOPP_DLL FileStore : public Store, private FilterPutSpaceHelper, public NotCopyable { public: /// \brief Exception thrown when file-based error is encountered class Err : public Exception { public: Err(const std::string &s) : Exception(IO_ERROR, s) {} }; /// \brief Exception thrown when file-based open error is encountered class OpenErr : public Err {public: OpenErr(const std::string &filename) : Err("FileStore: error opening file for reading: " + filename) {}}; /// \brief Exception thrown when file-based read error is encountered class ReadErr : public Err {public: ReadErr() : Err("FileStore: error reading file") {}};
/// \brief Construct a FileStore
FileStore() : m_stream(NULLPTR), m_space(NULLPTR), m_len(0), m_waiting(0) {}
/// \brief Construct a FileStore
/// \param in an existing stream
FileStore(std::istream &in) : m_stream(NULLPTR), m_space(NULLPTR), m_len(0), m_waiting(0)
{StoreInitialize(MakeParameters(Name::InputStreamPointer(), &in));}
/// \brief Construct a FileStore
/// \param filename the narrow name of the file to open
FileStore(const char *filename) : m_stream(NULLPTR), m_space(NULLPTR), m_len(0), m_waiting(0)
{StoreInitialize(MakeParameters(Name::InputFileName(), filename ? filename : ""));}
#if defined(CRYPTOPP_UNIX_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING) || _MSC_VER >= 1400 /// \brief Construct a FileStore /// \param filename the Unicode name of the file to open /// \details On non-Windows OS, this function assumes that setlocale() has been called. FileStore(const wchar_t *filename) {StoreInitialize(MakeParameters(Name::InputFileNameWide(), filename));} #endif
/// \brief Retrieves the internal stream
/// \returns the internal stream pointer
std::istream* GetStream() {return m_stream;}
/// \brief Retrieves the internal stream
/// \returns the internal stream pointer
const std::istream* GetStream() const {return m_stream;}
lword MaxRetrievable() const;
size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true);
size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const;
lword Skip(lword skipMax=ULONG_MAX);
private: void StoreInitialize(const NameValuePairs ¶meters);
member_ptr<std::ifstream> m_file;
std::istream *m_stream;
byte *m_space;
size_t m_len;
bool m_waiting;
};
/// \brief Implementation of Store interface /// \details file-based implementation of Store interface class CRYPTOPP_DLL FileSource : public SourceTemplate { public: typedef FileStore::Err Err; typedef FileStore::OpenErr OpenErr; typedef FileStore::ReadErr ReadErr;
/// \brief Construct a FileSource
FileSource(BufferedTransformation *attachment = NULLPTR)
: SourceTemplate<FileStore>(attachment) {}
/// \brief Construct a FileSource
/// \param in an existing stream
/// \param pumpAll flag indicating if source data should be pumped to its attached transformation
/// \param attachment an optional attached transformation
FileSource(std::istream &in, bool pumpAll, BufferedTransformation *attachment = NULLPTR)
: SourceTemplate<FileStore>(attachment) {SourceInitialize(pumpAll, MakeParameters(Name::InputStreamPointer(), &in));}
/// \brief Construct a FileSource
/// \param filename the narrow name of the file to open
/// \param pumpAll flag indicating if source data should be pumped to its attached transformation
/// \param attachment an optional attached transformation
/// \param binary flag indicating if the file is binary
FileSource(const char *filename, bool pumpAll, BufferedTransformation *attachment = NULLPTR, bool binary=true)
: SourceTemplate<FileStore>(attachment) {SourceInitialize(pumpAll, MakeParameters(Name::InputFileName(), filename)(Name::InputBinaryMode(), binary));}
#if defined(CRYPTOPP_UNIX_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING) || _MSC_VER >= 1400 /// \brief Construct a FileSource /// \param filename the Unicode name of the file to open /// \param pumpAll flag indicating if source data should be pumped to its attached transformation /// \param attachment an optional attached transformation /// \param binary flag indicating if the file is binary /// \details On non-Windows OS, this function assumes that setlocale() has been called. FileSource(const wchar_t *filename, bool pumpAll, BufferedTransformation *attachment = NULLPTR, bool binary=true) : SourceTemplate(attachment) {SourceInitialize(pumpAll, MakeParameters(Name::InputFileNameWide(), filename)(Name::InputBinaryMode(), binary));} #endif
/// \brief Retrieves the internal stream
/// \returns the internal stream pointer
std::istream* GetStream() {return m_store.GetStream();}
};
/// \brief Implementation of Store interface /// \details file-based implementation of Sink interface class CRYPTOPP_DLL FileSink : public Sink, public NotCopyable { public: /// \brief Exception thrown when file-based error is encountered class Err : public Exception { public: Err(const std::string &s) : Exception(IO_ERROR, s) {} }; /// \brief Exception thrown when file-based open error is encountered class OpenErr : public Err {public: OpenErr(const std::string &filename) : Err("FileSink: error opening file for writing: " + filename) {}}; /// \brief Exception thrown when file-based write error is encountered class WriteErr : public Err {public: WriteErr() : Err("FileSink: error writing file") {}};
/// \brief Construct a FileSink
FileSink() : m_stream(NULLPTR) {}
/// \brief Construct a FileSink
/// \param out an existing stream
FileSink(std::ostream &out)
{IsolatedInitialize(MakeParameters(Name::OutputStreamPointer(), &out));}
/// \brief Construct a FileSink
/// \param filename the narrow name of the file to open
/// \param binary flag indicating if the file is binary
FileSink(const char *filename, bool binary=true)
{IsolatedInitialize(MakeParameters(Name::OutputFileName(), filename)(Name::OutputBinaryMode(), binary));}
#if defined(CRYPTOPP_UNIX_AVAILABLE) || _MSC_VER >= 1400 /// \brief Construct a FileSink /// \param filename the Unicode name of the file to open /// \details On non-Windows OS, this function assumes that setlocale() has been called. FileSink(const wchar_t *filename, bool binary=true) {IsolatedInitialize(MakeParameters(Name::OutputFileNameWide(), filename)(Name::OutputBinaryMode(), binary));} #endif
/// \brief Retrieves the internal stream
/// \returns the internal stream pointer
std::ostream* GetStream() {return m_stream;}
void IsolatedInitialize(const NameValuePairs ¶meters);
size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking);
bool IsolatedFlush(bool hardFlush, bool blocking);
private: member_ptrstd::ofstream m_file; std::ostream *m_stream; };
NAMESPACE_END
#endif
//filters.h===================================================================================== // filters.h - originally written and placed in the public domain by Wei Dai
/// \file filters.h /// \brief Implementation of BufferedTransformation's attachment interface.
#ifndef CRYPTOPP_FILTERS_H #define CRYPTOPP_FILTERS_H
#include "cryptlib.h"
#if CRYPTOPP_MSC_VERSION
#endif
#include "cryptlib.h" #include "simple.h" #include "secblock.h" #include "misc.h" #include "smartptr.h" #include "queue.h" #include "algparam.h" #include "stdcpp.h"
NAMESPACE_BEGIN(CryptoPP)
/// \brief Implementation of BufferedTransformation's attachment interface /// \details Filter is a cornerstone of the Pipeline trinitiy. Data flows from /// Sources, through Filters, and then terminates in Sinks. The difference /// between a Source and Filter is a Source \a pumps data, while a Filter does /// not. The difference between a Filter and a Sink is a Filter allows an /// attached transformation, while a Sink does not. /// \details See the discussion of BufferedTransformation in cryptlib.h for /// more details. class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Filter : public BufferedTransformation, public NotCopyable { public: virtual ~Filter() {}
/// \name ATTACHMENT
//@{
/// \brief Construct a Filter
/// \param attachment an optional attached transformation
/// \details attachment can be \p NULL.
Filter(BufferedTransformation *attachment = NULLPTR);
/// \brief Determine if attachable
/// \returns \p true if the object allows attached transformations, \p false otherwise.
/// \note Source and Filter offer attached transformations; while Sink does not.
bool Attachable() {return true;}
/// \brief Retrieve attached transformation
/// \returns pointer to a BufferedTransformation if there is an attached transformation, \p NULL otherwise.
BufferedTransformation *AttachedTransformation();
/// \brief Retrieve attached transformation
/// \returns pointer to a BufferedTransformation if there is an attached transformation, \p NULL otherwise.
const BufferedTransformation *AttachedTransformation() const;
/// \brief Replace an attached transformation
/// \param newAttachment an optional attached transformation
/// \details newAttachment can be a single filter, a chain of filters or \p NULL.
/// Pass \p NULL to remove an existing BufferedTransformation or chain of filters
void Detach(BufferedTransformation *newAttachment = NULLPTR);
//@}
// See the documentation for BufferedTransformation in cryptlib.h
size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true);
size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const;
// See the documentation for BufferedTransformation in cryptlib.h
void Initialize(const NameValuePairs ¶meters=g_nullNameValuePairs, int propagation=-1);
bool Flush(bool hardFlush, int propagation=-1, bool blocking=true);
bool MessageSeriesEnd(int propagation=-1, bool blocking=true);
protected: virtual BufferedTransformation * NewDefaultAttachment() const; void Insert(Filter *nextFilter); // insert filter after this one
virtual bool ShouldPropagateMessageEnd() const {return true;}
virtual bool ShouldPropagateMessageSeriesEnd() const {return true;}
void PropagateInitialize(const NameValuePairs ¶meters, int propagation);
/// \brief Forward processed data on to attached transformation
/// \param outputSite unknown, system crash between keyboard and chair...
/// \param inString the byte buffer to process
/// \param length the size of the string, in bytes
/// \param messageEnd means how many filters to signal MessageEnd() to, including this one
/// \param blocking specifies whether the object should block when processing input
/// \param channel the channel to process the data
/// \returns the number of bytes that remain in the block (i.e., bytes not processed)
size_t Output(int outputSite, const byte *inString, size_t length, int messageEnd, bool blocking, const std::string &channel=DEFAULT_CHANNEL);
/// \brief Output multiple bytes that may be modified by callee.
/// \param outputSite unknown, system crash between keyboard and chair...
/// \param inString the byte buffer to process
/// \param length the size of the string, in bytes
/// \param messageEnd means how many filters to signal MessageEnd() to, including this one
/// \param blocking specifies whether the object should block when processing input
/// \param channel the channel to process the data
/// \returns the number of bytes that remain in the block (i.e., bytes not processed)
size_t OutputModifiable(int outputSite, byte *inString, size_t length, int messageEnd, bool blocking, const std::string &channel=DEFAULT_CHANNEL);
/// \brief Signals the end of messages to the object
/// \param outputSite unknown, system crash between keyboard and chair...
/// \param propagation the number of attached transformations the MessageEnd() signal should be passed
/// \param blocking specifies whether the object should block when processing input
/// \param channel the channel to process the data
/// \returns TODO
/// \details propagation count includes this object. Setting propagation to <tt>1</tt> means this
/// object only. Setting propagation to <tt>-1</tt> means unlimited propagation.
bool OutputMessageEnd(int outputSite, int propagation, bool blocking, const std::string &channel=DEFAULT_CHANNEL);
/// \brief Flush buffered input and/or output, with signal propagation
/// \param outputSite unknown, system crash between keyboard and chair...
/// \param hardFlush is used to indicate whether all data should be flushed
/// \param propagation the number of attached transformations the Flush() signal should be passed
/// \param blocking specifies whether the object should block when processing input
/// \param channel the channel to process the data
/// \returns TODO
/// \details propagation count includes this object. Setting propagation to <tt>1</tt> means this
/// object only. Setting propagation to <tt>-1</tt> means unlimited propagation.
/// \note Hard flushes must be used with care. It means try to process and output everything, even if
/// there may not be enough data to complete the action. For example, hard flushing a HexDecoder
/// would cause an error if you do it after inputing an odd number of hex encoded characters.
/// \note For some types of filters, like ZlibDecompressor, hard flushes can only
/// be done at "synchronization points". These synchronization points are positions in the data
/// stream that are created by hard flushes on the corresponding reverse filters, in this
/// example ZlibCompressor. This is useful when zlib compressed data is moved across a
/// network in packets and compression state is preserved across packets, as in the SSH2 protocol.
bool OutputFlush(int outputSite, bool hardFlush, int propagation, bool blocking, const std::string &channel=DEFAULT_CHANNEL);
/// \brief Marks the end of a series of messages, with signal propagation
/// \param outputSite unknown, system crash between keyboard and chair...
/// \param propagation the number of attached transformations the MessageSeriesEnd() signal should be passed
/// \param blocking specifies whether the object should block when processing input
/// \param channel the channel to process the data
/// \returns TODO
/// \details Each object that receives the signal will perform its processing, decrement
/// propagation, and then pass the signal on to attached transformations if the value is not 0.
/// \details propagation count includes this object. Setting propagation to <tt>1</tt> means this
/// object only. Setting propagation to <tt>-1</tt> means unlimited propagation.
/// \note There should be a MessageEnd() immediately before MessageSeriesEnd().
bool OutputMessageSeriesEnd(int outputSite, int propagation, bool blocking, const std::string &channel=DEFAULT_CHANNEL);
private: member_ptr m_attachment;
protected: size_t m_inputPosition; int m_continueAt; };
/// \brief Create a working space in a BufferedTransformation struct CRYPTOPP_DLL FilterPutSpaceHelper { virtual ~FilterPutSpaceHelper() {}
/// \brief Create a working space in a BufferedTransformation
/// \param target BufferedTransformation for the working space
/// \param channel channel for the working space
/// \param minSize minimum size of the allocation, in bytes
/// \param desiredSize preferred size of the allocation, in bytes
/// \param bufferSize actual size of the allocation, in bytes
/// \pre <tt>desiredSize >= minSize</tt> and <tt>bufferSize >= minSize</tt>.
/// \details \p bufferSize is an IN and OUT parameter. If HelpCreatePutSpace() returns a non-NULL value, then
/// bufferSize is valid and provides the size of the working space created for the caller.
/// \details Internally, HelpCreatePutSpace() calls \ref BufferedTransformation::ChannelCreatePutSpace
/// "ChannelCreatePutSpace()" using \p desiredSize. If the target returns \p desiredSize with a size less
/// than \p minSize (i.e., the request could not be fulfilled), then an internal SecByteBlock
/// called \p m_tempSpace is resized and used for the caller.
byte *HelpCreatePutSpace(BufferedTransformation &target, const std::string &channel, size_t minSize, size_t desiredSize, size_t &bufferSize)
{
CRYPTOPP_ASSERT(desiredSize >= minSize && bufferSize >= minSize);
if (m_tempSpace.size() < minSize)
{
byte *result = target.ChannelCreatePutSpace(channel, desiredSize);
if (desiredSize >= minSize)
{
bufferSize = desiredSize;
return result;
}
m_tempSpace.New(bufferSize);
}
bufferSize = m_tempSpace.size();
return m_tempSpace.begin();
}
/// \brief Create a working space in a BufferedTransformation
/// \param target the BufferedTransformation for the working space
/// \param channel channel for the working space
/// \param minSize minimum size of the allocation, in bytes
/// \details Internally, the overload calls HelpCreatePutSpace(BufferedTransformation &target, const std::string &channel, size_t minSize, size_t desiredSize, size_t &bufferSize) using \p minSize for missing arguments.
byte *HelpCreatePutSpace(BufferedTransformation &target, const std::string &channel, size_t minSize)
{return HelpCreatePutSpace(target, channel, minSize, minSize, minSize);}
/// \brief Create a working space in a BufferedTransformation
/// \param target the BufferedTransformation for the working space
/// \param channel channel for the working space
/// \param minSize minimum size of the allocation, in bytes
/// \param bufferSize the actual size of the allocation, in bytes
/// \details Internally, the overload calls HelpCreatePutSpace(BufferedTransformation &target, const std::string &channel, size_t minSize, size_t desiredSize, size_t &bufferSize) using \p minSize for missing arguments.
byte *HelpCreatePutSpace(BufferedTransformation &target, const std::string &channel, size_t minSize, size_t bufferSize)
{return HelpCreatePutSpace(target, channel, minSize, minSize, bufferSize);}
/// \brief Temporay working space
SecByteBlock m_tempSpace;
};
/// \brief Measure how many bytes and messages pass through the filter /// \details measure how many bytes and messages pass through the filter. The filter also serves as valve by /// maintaining a list of ranges to skip during processing. class CRYPTOPP_DLL MeterFilter : public Bufferless { public: virtual ~MeterFilter() {}
/// \brief Construct a MeterFilter
/// \param attachment an optional attached transformation
/// \param transparent flag indicating if the filter should function transparently
/// \details \p attachment can be \p NULL. The filter is transparent by default. If the filter is
/// transparent, then PutMaybeModifiable() does not process a request and always returns 0.
MeterFilter(BufferedTransformation *attachment=NULLPTR, bool transparent=true)
: m_transparent(transparent), m_currentMessageBytes(0), m_totalBytes(0)
, m_currentSeriesMessages(0), m_totalMessages(0), m_totalMessageSeries(0)
, m_begin(NULLPTR), m_length(0) {Detach(attachment); ResetMeter();}
/// \brief Set or change the transparent mode of this object
/// \param transparent the new transparent mode
void SetTransparent(bool transparent) {m_transparent = transparent;}
/// \brief Adds a range to skip during processing
/// \param message the message to apply the range
/// \param position the 0-based index in the current stream
/// \param size the length of the range
/// \param sortNow flag indicating whether the range should be sorted
/// \details Internally, MeterFilter maitains a deque of ranges to skip. As messages are processed,
/// ranges of bytes are skipped according to the list of ranges.
void AddRangeToSkip(unsigned int message, lword position, lword size, bool sortNow = true);
/// \brief Resets the meter
/// \details ResetMeter() reinitializes the meter by setting counters to 0 and removing previous
/// skip ranges.
void ResetMeter();
void IsolatedInitialize(const NameValuePairs ¶meters)
{CRYPTOPP_UNUSED(parameters); ResetMeter();}
lword GetCurrentMessageBytes() const {return m_currentMessageBytes;}
lword GetTotalBytes() const {return m_totalBytes;}
unsigned int GetCurrentSeriesMessages() const {return m_currentSeriesMessages;}
unsigned int GetTotalMessages() const {return m_totalMessages;}
unsigned int GetTotalMessageSeries() const {return m_totalMessageSeries;}
byte * CreatePutSpace(size_t &size)
{return AttachedTransformation()->CreatePutSpace(size);}
size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking);
size_t PutModifiable2(byte *inString, size_t length, int messageEnd, bool blocking);
bool IsolatedMessageSeriesEnd(bool blocking);
private: size_t PutMaybeModifiable(byte *inString, size_t length, int messageEnd, bool blocking, bool modifiable); bool ShouldPropagateMessageEnd() const {return m_transparent;} bool ShouldPropagateMessageSeriesEnd() const {return m_transparent;}
struct MessageRange
{
inline bool operator<(const MessageRange &b) const // BCB2006 workaround: this has to be a member function
{return message < b.message || (message == b.message && position < b.position);}
unsigned int message; lword position; lword size;
};
bool m_transparent;
lword m_currentMessageBytes, m_totalBytes;
unsigned int m_currentSeriesMessages, m_totalMessages, m_totalMessageSeries;
std::deque<MessageRange> m_rangesToSkip;
byte *m_begin;
size_t m_length;
};
/// \brief A transparent MeterFilter /// \sa MeterFilter, OpaqueFilter class CRYPTOPP_DLL TransparentFilter : public MeterFilter { public: /// \brief Construct a TransparentFilter /// \param attachment an optional attached transformation TransparentFilter(BufferedTransformation *attachment=NULLPTR) : MeterFilter(attachment, true) {} };
/// \brief A non-transparent MeterFilter /// \sa MeterFilter, TransparentFilter class CRYPTOPP_DLL OpaqueFilter : public MeterFilter { public: /// \brief Construct an OpaqueFilter /// \param attachment an optional attached transformation OpaqueFilter(BufferedTransformation *attachment=NULLPTR) : MeterFilter(attachment, false) {} };
/// \brief Divides an input stream into discrete blocks /// \details FilterWithBufferedInput divides the input stream into a first block, a number of /// middle blocks, and a last block. First and last blocks are optional, and middle blocks may /// be a stream instead (i.e. blockSize == 1). /// \sa AuthenticatedEncryptionFilter, AuthenticatedDecryptionFilter, HashVerificationFilter, /// SignatureVerificationFilter, StreamTransformationFilter class CRYPTOPP_DLL FilterWithBufferedInput : public Filter { public: virtual ~FilterWithBufferedInput() {}
/// \brief Construct a FilterWithBufferedInput with an attached transformation
/// \param attachment an attached transformation
FilterWithBufferedInput(BufferedTransformation *attachment);
/// \brief Construct a FilterWithBufferedInput with an attached transformation
/// \param firstSize the size of the first block
/// \param blockSize the size of middle blocks
/// \param lastSize the size of the last block
/// \param attachment an attached transformation
/// \details \p firstSize and \p lastSize may be 0. \p blockSize must be at least 1.
FilterWithBufferedInput(size_t firstSize, size_t blockSize, size_t lastSize, BufferedTransformation *attachment);
void IsolatedInitialize(const NameValuePairs ¶meters);
size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking)
{
return PutMaybeModifiable(const_cast<byte *>(inString), length, messageEnd, blocking, false);
}
size_t PutModifiable2(byte *inString, size_t length, int messageEnd, bool blocking)
{
return PutMaybeModifiable(inString, length, messageEnd, blocking, true);
}
/// \brief Flushes data buffered by this object, without signal propagation
/// \param hardFlush indicates whether all data should be flushed
/// \param blocking specifies whether the object should block when processing input
/// \details IsolatedFlush() calls ForceNextPut() if hardFlush is true