I have a simplest possible example of sha256 written in C, using the openSSL library.
// compile with: gcc -o sha256 sha256.c -lcrypto
#include <openssl/sha.h>
#include <stdio.h>
int main(int argc, char **argv)
{
unsigned char buffer[BUFSIZ];
FILE *f;
SHA256_CTX ctx;
size_t len;
if (argc < 2) {
fprintf(stderr, "usage: %s <file>\n", argv[0]);
return 1;
}
f = fopen(argv[1], "r");
if (!f) {
fprintf(stderr, "couldn't open %s\n", argv[1]);
return 1;
}
SHA256_Init(&ctx);
do {
len = fread(buffer, 1, BUFSIZ, f);
SHA256_Update(&ctx, buffer, len);
} while (len == BUFSIZ);
SHA256_Final(buffer, &ctx);
fclose(f);
for (len = 0; len < SHA256_DIGEST_LENGTH; ++len)
printf("%02x", buffer[len]);
putchar('\n');
return 0;
}
I need the same for sha1, but I could not find similar simple example that actually works. The naive approach of replacing occurrences of SHA256 in the above code with SHA1 does not work (obviously).
How can I modify my program for SHA1 ?
UPDATE
as suggested by #dbush, I have used his EVP code, and integrated it into my program. My program now looks like this:
#include <stdio.h>
#include <openssl/sha.h>
#include <openssl/evp.h>
#include <openssl/err.h>
int main(int argc, char **argv)
{
FILE *f;
size_t len;
unsigned char buffer[BUFSIZ];
if (argc < 2) {
fprintf(stderr, "usage: %s <file>\n", argv[0]);
return 1;
}
f = fopen(argv[1], "r");
if (!f) {
fprintf(stderr, "couldn't open %s\n", argv[1]);
return 1;
}
EVP_MD_CTX hashctx;
//EVP_MD *hashptr = EVP_get_digestbyname("SHA256");
EVP_MD *hashptr = EVP_get_digestbyname("SHA1");
EVP_MD_CTX_init(&hashctx);
EVP_DigestInit_ex(&hashctx, hashptr, NULL));
do {
len = fread(buffer, 1, BUFSIZ, f);
EVP_DigestUpdate(&hashctx, buffer, len);
} while (len == BUFSIZ);
EVP_DigestFinal_ex(&hashctx, buffer, &len);
EVP_MD_CTX_cleanup(&hashctx);
fclose(f);
int i;
for (i = 0; i < len; ++i)
printf("%02x", buffer[i]);
return 0;
}
When I compile it using gcc -o evp evp.c -lcrypto, I get couple of errors, such as:
evp.c: In function ‘main’:
evp.c:29:19: warning: initialization discards ‘const’ qualifier from pointer target type [enabled by default]
evp.c:32:43: error: expected ‘;’ before ‘)’ token
evp.c:32:43: error: expected statement before ‘)’ token
evp.c:39:1: warning: passing argument 3 of ‘EVP_DigestFinal_ex’ from incompatible pointer type [enabled by default]
In file included from evp.c:4:0:
/usr/include/openssl/evp.h:574:5: note: expected ‘unsigned int *’ but argument is of type ‘size_t *’
Rather than using the SHA1 or SHA256 specific functions, use the EVP_Digest* family of functions which work with any hash.
...
// makes all algorithms available to the EVP* routines
OpenSSL_add_all_algorithms();
// load the error strings for ERR_error_string
ERR_load_crypto_strings();
EVP_MD_CTX hashctx;
//const EVP_MD *hashptr = EVP_get_digestbyname("SHA256");
const EVP_MD *hashptr = EVP_get_digestbyname("SHA1");
EVP_MD_CTX_init(&hashctx);
EVP_DigestInit_ex(&hashctx, hashptr, NULL);
do {
len = fread(buffer, 1, BUFSIZ, f);
EVP_DigestUpdate(&hashctx, buffer, len);
} while (len == BUFSIZ);
unsigned int outlen;
EVP_DigestFinal_ex(&hashctx, buffer, &outlen);
EVP_MD_CTX_cleanup(&hashctx);
fclose(f);
int i;
for (i = 0; i < outlen; ++i)
printf("%02x", buffer[i]);
I've omitted the error checking for brevity. To check for errors, do the following:
if (function_to_check() == 0) {
char errstr[1000];
ERR_error_string(ERR_get_error(), errstr);
printf("error: %s\n", errstr;
}
EDIT:
There were some error in the above code that have been corrected:
hashptr was declared EVP_MD *, is now const EVP_MD *.
The call to EVP_DigestInit_ex had an extra parenthesis at the end
The third parameter to EVP_DigestFinal_ex is specifically given an unsigned int * instead a size_t *, which may not necessarily be the same.
Added calls to two OpenSSL initialization functions at the top
You can simply do like this:-
#include <openssl/sha.h>
#include <stdio.h>
int main(int argc, char **argv)
{
unsigned char buffer[BUFSIZ];
FILE *f;
SHA_CTX ctx;
size_t len;
if (argc < 2) {
fprintf(stderr, "usage: %s <file>\n", argv[0]);
return 1;
}
f = fopen(argv[1], "r");
if (!f) {
fprintf(stderr, "couldn't open %s\n", argv[1]);
return 1;
}
SHA1_Init(&ctx);
do {
len = fread(buffer, 1, BUFSIZ, f);
SHA1_Update(&ctx, buffer, len);
} while (len == BUFSIZ);
SHA1_Final(buffer, &ctx);
fclose(f);
for (len = 0; len < SHA_DIGEST_LENGTH; ++len)
printf("%02x", buffer[len]);
putchar('\n');
return 0;
}
Related
I am trying to read from a file, and here is my code, but as I run my code nothing shows up. Have I used the getline() function incorrectly? I can not understand my problem.
const char *READ = "r";
/**
* main - Entry point of my program
*
* Return: On success, it returns 0. On
* error it returns -1
*/
int main(int ac, char **av)
{
FILE *fpointer;
char *lineptr = NULL;
size_t *n = 0;
int line_number = 1;
if (ac != 2)
{
fprintf(stderr, "USAGE: monty file\n");
exit(EXIT_FAILURE);
}
fpointer = fopen(av[1], READ);
if (fpointer == NULL)
{
fprintf(stderr, "Error: Can't open file %s\n", av[1]);
exit(EXIT_FAILURE);
}
while (getline(&lineptr, n, fpointer) != -1)
{
printf("Line %d: %s\n", line_number, lineptr);
line_number++;
}
return (0);
}
getline(&lineptr, n, fpointer) returns -1. You did not explicitly check this and print an error message.
Checking errno it's because of EINVAL: invalid argument. Also good to check errno.
Reason is that n is NULL, while a pointer to an existing size_t is required.
BTW, indenting with 8 spaces is rather uncommon; I'd stay with 4 space. (Also, never use TAB characters.)
It's advisable to stick with extremely common argc and argv.
Nice you put {s on a further empty line; I like that style.
You'd get this:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
const char *READ = "r";
int main(int argc, char **argv)
{
FILE *fpointer;
char *lineptr = NULL;
size_t n;
int line_number = 1;
if (argc != 2)
{
fprintf(stderr, "USAGE: monty file\n");
exit(EXIT_FAILURE);
}
fpointer = fopen(argv[1], READ);
if (fpointer == NULL)
{
fprintf(stderr, "Error: Can't open file '%s'.\n", argv[1]);
exit(EXIT_FAILURE);
}
if (getline(&lineptr, &n, fpointer) == -1)
{
printf("Failed to read file '%s': %s.\n", argv[1], strerror(errno));
exit(EXIT_FAILURE);
}
do
{
printf("Line %4d: %s\n", line_number, lineptr);
line_number++;
}
while (getline(&lineptr, &n, fpointer) != -1);
return (0);
}
Declaration of getline:
ssize_t getline(char **lineptr, size_t *n, FILE *stream);
As an output parameter, the type of n is size_t *. It points to a space for writing by getline.
But in your code, n points to 0, which is NOT a vaild addr to write in.
I wrote a program that copies the standard entry into the stdout as well as into a file. The program works but I have a problem, I receive a warning when compiling with make:
warning: implicit declaration of function ‘isprint’ [-Wimplicit-function-declaration]
if (isprint(optopt))
^~~
code:
Although it's not a big deal, I'd like it to stop displaying this warning. What would be the problem? I would also like a review of the code, what could I improve?
The program behaves like the tee -a file command.
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
static int append_mode = 0;
int parse_args(int argc, char *argv[])
{
char c;
while ((c = getopt(argc, argv, "a")) != -1) {
switch (c) {
case 'a':
append_mode = 1;
break;
case '?':
if (isprint(optopt))
fprintf(stderr, "Unkonw option `-%c'.\n", optopt);
else
fprintf(stderr,
"Unknown option character `\\x%x'.\n", optopt);
return 1;
default:
abort();
break;
}
}
return 0;
}
int main(int argc, char *argv[])
{
char buf[100];
size_t len;
char *file_mode;
int i;
FILE *files[20];
int num_files;
if (parse_args(argc, argv)) {
return 1;
}
file_mode = (append_mode ? "a" : "w");
num_files = argc - optind;
if (num_files > 0) {
if (files == NULL) {
fprintf(stderr, "Unable to allocate file buffer space\n");
return 1;
}
/* go through file arguments and either open for writing
or append based on the -a flag */
for (i = optind; i < argc; i++) {
FILE *pFile = fopen(argv[i], file_mode);
if (pFile == NULL)
{
fprintf(stderr, "Unable to open file %s for mode %s",
argv[i], file_mode);
goto main_cleanup;
}
files[i - optind] = pFile; /* mind the offset */
}
}
FILE *not_stdin = fopen("tee.c", "r");
while ((len = fread(&buf[0], 1, sizeof(buf), not_stdin)) > 0) {
fwrite(&buf[0], 1, len, stdout);
for (i = 0; i < num_files; i++) {
fwrite(&buf[0], 1, len, files[i]);
}
}
main_cleanup:
if (num_files > 0) {
for (i = 0; i < num_files; i++) {
fclose(files[i]);
}
}
return 0;
}
Mostly this warning appears when you are trying to use a function without including its required header.
To use isprint() add #include <ctype.h> to your included headers.
I am trying to parse uevent using this below code but I think my regular expression is not proper causing regcomp function to fail.
Can anyone help? I am trying to do something like this.
#include <stdio.h>
#include <string.h>
#include <regex.h>
int main ()
{
char * source = "change#/devices/soc/799999.i2c/i2c-3/3-0015/power_supply/battery";
char * regexString = "(?<action>[a-zA-Z]+)#\\/(?<dev_path>.*)\\/(?<subsystem>[a-zA-z]+)\\/(?<name>[a-zA-z]+)";
size_t maxGroups = 4;
regex_t regexCompiled;
regmatch_t groupArray[maxGroups];
if (regcomp(®exCompiled, regexString, REG_EXTENDED))
{
printf("Could not compile regular expression.\n");
return 1;
};
regfree(®exCompiled);
return 0;
}
I am getting "Could not compile regular expression.". It means regcomp didn't recognize the regex.
When I report on the error using the code:
#include <stdio.h>
#include <string.h>
#include <regex.h>
int main(void)
{
//char * source = "change#/devices/soc/799999.i2c/i2c-3/3-0015/power_supply/battery";
char * regexString = "(?<action>[a-zA-Z]+)#\\/(?<dev_path>.*)\\/(?<subsystem>[a-zA-z]+)\\/(?<name>[a-zA-z]+)";
//size_t maxGroups = 4;
regex_t regexCompiled;
//regmatch_t groupArray[maxGroups];
int rc;
if ((rc = regcomp(®exCompiled, regexString, REG_EXTENDED)) != 0)
{
char buffer[1024];
regerror(rc, ®exCompiled, buffer, sizeof(buffer));
printf("Could not compile regular expression (%d: %s).\n", rc, buffer);
return 1;
}
regfree(®exCompiled);
return 0;
}
I get the output:
Could not compile regular expression (13: repetition-operator operand invalid).
The problem is in the notation (? you are using:
"(?<action>[a-zA-Z]+)#\\/(?<dev_path>.*)\\/(?<subsystem>[a-zA-z]+)\\/(?<name>[a-zA-z]+)"
That notation is for PCRE and not POSIX. And PCRE uses ? after ( precisely because it isn't valid in other regex systems (such as POSIX).
So, if you want to use PCRE regexes, install and use the PCRE library.
Otherwise, you'll need to use:
"([a-zA-Z]+)#\\/(.*)\\/([a-zA-z]+)\\/([a-zA-z]+)"
With that in place, and noting that you need a regmatch_t for the whole of the string that's matched plus 4 captured groups (for a total of 5 captures), you can write:
#include <stdio.h>
#include <string.h>
#include <regex.h>
int main(void)
{
char *source = "change#/devices/soc/799999.i2c/i2c-3/3-0015/power_supply/battery";
// char * regexString = "(?<action>[a-zA-Z]+)#\\/(?<dev_path>.*)\\/(?<subsystem>[a-zA-z]+)\\/(?<name>[a-zA-z]+)";
size_t maxGroups = 5;
char *regexString = "([a-zA-Z]+)#\\/(.*)\\/([a-zA-z]+)\\/([a-zA-z]+)";
regex_t regexCompiled;
regmatch_t groupArray[maxGroups];
int rc;
if ((rc = regcomp(®exCompiled, regexString, REG_EXTENDED)) != 0)
{
char buffer[1024];
regerror(rc, ®exCompiled, buffer, sizeof(buffer));
printf("Could not compile regular expression (%d: %s).\n", rc, buffer);
return 1;
}
if ((rc = regexec(®exCompiled, source, maxGroups, groupArray, 0)) != 0)
{
char buffer[1024];
regerror(rc, ®exCompiled, buffer, sizeof(buffer));
printf("Could not execute regular expression (%d: %s).\n", rc, buffer);
return 1;
}
printf("Match successful:\n");
for (size_t i = 0; i < maxGroups; i++)
{
int so = groupArray[i].rm_so;
int eo = groupArray[i].rm_eo;
printf("%zu: %d..%d [%.*s]\n", i, so, eo, eo - so, &source[so]);
}
regfree(®exCompiled);
return 0;
}
and the output is:
Match successful:
0: 0..64 [change#/devices/soc/799999.i2c/i2c-3/3-0015/power_supply/battery]
1: 0..6 [change]
2: 8..43 [devices/soc/799999.i2c/i2c-3/3-0015]
3: 44..56 [power_supply]
4: 57..64 [battery]
I have a problem at my C-lecture skill practice. My exercise is to read a text document (which is in the same directory like the program) char by char and write it reversed (so from the end to the beginning, char by char) at the Terminal (i have to work at Ubuntu).
Unfortunately it doesn't work - "read" only reads newline-chars (\n).
Can you find my mistake?
#include <sys/stat.h> //mode_t: accessing rights for the file
#include <fcntl.h> //for I/O
#include <unistd.h> //for file descriptors
#include <string.h> //for strlen
short const EXIT_FAILURE = 1;
short const EXIT_SUCCESS = 0;
char const* USAGE_CMD = "usage: write_file filename string_to_write\n";
char const* ERR_OPEN = "error in open\n";
char const* ERR_READ = "error in reading\n";
char const* ERR_CLOSE = "error in close\n";
char const* ERR_WRITE = "error in write\n";
int main(int argc, char** argv){
int fd = open(argv[1], O_RDONLY);
if(fd == -1){
write(STDERR_FILENO, ERR_OPEN, strlen(ERR_OPEN));
return EXIT_FAILURE;
}
int two_char_back = (-1)*sizeof(char); //shift-value for char
int one_back = -1; //shift-value for "no shift"
int length = lseek(fd, one_back, SEEK_END);//setting to one before oef
int i = 0; //for the loop
char buffer;
char* pbuffer = &buffer; //buffer for writing
while (i < length){
if (read(fd, pbuffer, sizeof(buffer)) == -1){ //READING
write(STDERR_FILENO, ERR_READ, strlen(ERR_READ));
return EXIT_FAILURE;
}
if(write(STDOUT_FILENO, pbuffer, sizeof(buffer)) == -1){ //WRITING
write(STDERR_FILENO, ERR_WRITE, strlen(ERR_WRITE));
return EXIT_FAILURE;
}
lseek(fd, two_char_back, SEEK_CUR); //STEPPING
i++;
}
if(close(fd) == -1){ //CLOSING
write(STDERR_FILENO, ERR_CLOSE, strlen(ERR_CLOSE));
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
This is wrong:
int two_char_back = (-1)*sizeof(char);
sizeof(char) is 1, you need -2
Haven't tried running it, but looks like two_char_back should be -2. The read advances the cursor, so -1 keeps reading the same one.
Also, just an option, you could make it more efficient by reading the whole file in then reversing it, then writing.
You have a typo in following line:
int two_char_back = (-1)*sizeof(char);
It must be:
int two_char_back = (-2)*sizeof(char);
As read() increments a cursor, you are actually reading the same character all the time e.g:
example text
^
|
After reading:
example text
^
|
After seeking:
example text
^
|
Thanks for your advices a lot!
& Thanks to my colleagues!
Now it works but I created kind of a new version, here it is:
#include <sys/stat.h> //mode_t: accessing rights for the file
#include <fcntl.h> //for I/O
#include <unistd.h> //for file descriptors
#include <string.h> //for strlen
short const EXIT_FAILURE = 1;
short const EXIT_SUCCESS = 0;
char const* USAGE_CMD = "usage: write_file filename string_to_write\n";
char const* ERR_OPEN = "error in open\n";
char const* ERR_READ = "error in reading\n";
char const* ERR_CLOSE = "error in close\n";
char const* ERR_WRITE = "error in write\n";
int main(int argc, char** argv){
int fd = open(argv[1], O_RDONLY); //OPENING
if(fd == -1){
write(STDERR_FILENO, ERR_OPEN, strlen(ERR_OPEN));
return EXIT_FAILURE;
}
int file_size = lseek(fd, 0, SEEK_END); //setting to eof
int i = file_size-1; //for the loop, runs from the end to the start
char buffer;
//the files runs from the end to the back
do{
i--;
lseek(fd, i, SEEK_SET); //STEPPING from the start
if (read(fd, &buffer, sizeof(buffer)) != sizeof(buffer)){ //READING
write(STDERR_FILENO, ERR_READ, strlen(ERR_READ));
return EXIT_FAILURE;
}
if(write(STDOUT_FILENO, &buffer, sizeof(buffer)) != sizeof(buffer)){ //WRITING
write(STDERR_FILENO, ERR_WRITE, strlen(ERR_WRITE));
return EXIT_FAILURE;
}
}while (i != 0);
buffer = '\n';
write(STDOUT_FILENO, &buffer, sizeof(buffer));//no error-det. due to fixed value
if(close(fd) == -1){ //CLOSING
write(STDERR_FILENO, ERR_CLOSE, strlen(ERR_CLOSE));
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
I am just testing a small program that I want to test.
I am wondering if there is a way to use the stderr to display what the actual error was.
For example, if the file doesn't exist. Is there a standard error that I can display.
I am using stderr, and I thought by using that, I could display what the actual error was.
For example. If the file doesn't exit. Does any errors get sent to stderr that can be displayed?
I hope I am clear with my question.
Many thanks for any advice.
#include <stdio.h>
#include <string.h>
int main(void)
{
char buffer[100] = {'\0'}; /* declare and clean buffer */
FILE *fp;
int len_of_buff = 0;
fp = fopen("licenseURL.txt", "r");
if(fp == NULL)
{
fprintf(stderr, "There was a error opening a file ???");
exit(1);
}
fgets(buffer, sizeof(buffer), fp);
len_of_buff = strlen(buffer);
buffer[len_of_buff + 1] = '\0'; /* null terminate */
printf("The url is: [ %s ]\n", buffer);
fclose(fp);
}
Replace your fprintf(stderr, ...) call with:
perror("file open");
(stderr is just a stream for sending error messages to, so that they don't get mixed up with the normal program output - in case you're redirecting to a file or similar).
Use the strerror() function to retrieve a string describing the error.
My untested version would look like this:
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void
die(const char *errstr, ...) {
va_list ap;
va_start(ap, errstr);
vfprintf(stderr, errstr, ap);
va_end(ap);
exit(EXIT_FAILURE);
}
int
main(int argc, char **argv) {
static const char licenseURL[] = "licenseURL.txt";
static char buf[100]; /* declare a clean buffer */
FILE *fp;
size_t len = 0;
if(!(fp = fopen(licenseURL, "r")))
die("couldn't %s: %s\n", licenseURL, strerror(errno));
if(!fgets(buf, sizeof buf, fp))
die("fgets failed: %s\n", strerror(errno));
len = strlen(buf);
if(len > 1 && buf[len - 1] == '\n')
buf[len - 1] = '\0'; /* cut off trailing \n */
printf("The url is: [ %s ]\n", buf);
fclose(fp);
return 0;
}