-4

I wrote a code that writes a dictionary of passwords, but it doesn't write on the .txt file

The code generates a text file, then it writes all posibilities of passwords using the charset that I define, but it does not write on the text file.

This is the code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

void Dictionary_Generator(char *charset, int min, int max) {
    char *password = malloc((max + 1) * sizeof(char));
    if (password == NULL) {
        fprintf(stderr, "Error: memory allocation failed\n");
        exit(1);
    }

    FILE *file = fopen("dictionary.txt", "w");
    if (file == NULL) {
        fprintf(stderr, "Error: could not create file\n");
        exit(1);
    }

    int charset_length = strlen(charset);
    int num_combinations = pow(charset_length, max);

    for (int i = 0; i < num_combinations; i++) {
        int index = i;
        int length = min;
        while (index >= charset_length) {
            password[length - 1] = charset[index % charset_length];
            index /= charset_length;
            length++;
        }
        password[length - 1] = charset[index];
        password[length] = '\0';
        if (length >= min) {
            int result = fprintf(file, "%s\n", password);
            if (result < 0) {
                perror("Error writing to file");
                exit(1);
    }
        }
    }

    fclose(file);
    free(password);
}

int main() {
    char *charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    int min = 4;
    int max = 8;
    Dictionary_Generator(charset, min, max);
    return 0;
}

It generates a text file, but the file is empty.

  • 4
    This appears to be C code. Why is this question tagged C++ and cython? – Brian61354270 Mar 05 '23 at 19:49
  • 2
    This code [is not valid C++](https://godbolt.org/z/afeM4YbYd). – Drew Dormann Mar 05 '23 at 19:50
  • 1
    If when you "run" your code you're getting a linker error, you never actually ran it. It's failing to compile – Brian61354270 Mar 05 '23 at 19:50
  • This wouldn't be a valid way of generating "combinations" anyway, but, however you look at it, 62^8 will never fit in an int variable. – lastchance Mar 05 '23 at 19:54
  • I can't figure out what you think the code is doing, but I can tell you that your code never writes to the first three letters of the password array. The `length` variable starts at `min` (which is 4) and only increases. Therefore `password[length-1] = ...` never writes to the beginning of the password array – john Mar 05 '23 at 19:54
  • I think the code needs to be rethought and rewritten. – john Mar 05 '23 at 19:58
  • Have you tried running your code line-by-line in a debugger while monitoring the control flow and the values of all variables, in order to determine in which line your program stops behaving as intended? If you did not try this, then you may want to read this: [What is a debugger and how can it help me diagnose problems?](https://stackoverflow.com/q/25385173/12149471) You may also want to read this: [How to debug small programs?](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/) – Andreas Wenzel Mar 06 '23 at 00:35

2 Answers2

0

It appears this code assigns the string that ought to be written to the file to a variable, but doesn't actually write it to the file.

if (length >= min) {
        int result = fprintf(file, "%s\n", password);
        if (result < 0) {
            perror("Error writing to file");
            exit(1);
}
theeelgonzo13
  • 17
  • 1
  • 8
0

After fixing the undefined reference to 'pow' by adding -lm at the end of the cc line, you have another error:

charset_length is 62. max is 8.

So, when you do:

int num_combinations = pow(charset_length, max);

You are doing pow(62,8) which, when truncated to an int, you get a negative number. The result of the pow is on the order of 2.1e14, so far too large for an int.

So, the subsequent for loop will execute zero times.

You may want to use long long instead, but 2e14 iterations seems like a lot.

Doing:

int num_combinations = pow(charset_length, max - min);

seems more reasonable (and fits inside an int). But, in that case, your program just outputs blank lines.


UPDATE

When I've done a similar type of iteration, I've used a "helper" vector that is the current number width in length. I treat this an an N digit wide number in base(charset_length).

It takes values for each digit in the range of 0 to charset_length - 1.

I think it's easier to have the outer loop be output word length (e.g. 4-8) and then generate all words of that length from the charset

So, I had to do some considerable refactoring, splitting up the generation code into multiple functions.

The actual runtime is so large that I added progress output to stdout ...

Here is the refactored code. It is annotated:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>

// incbignum -- increment the base N number
// RETURNS: carryout/overflow
int
incbignum(unsigned char *bignum,int iwid,int base)
{
    int carry = 1;

    for (int idx = 0;  idx < iwid;  ++idx) {
        int val = bignum[idx];
        val += carry;

        carry = (val >= base);
        if (carry)
            val %= base;

        bignum[idx] = val;

        if (! carry)
            break;
    }

    return carry;
}

// tscgetf -- get time in fractional seconds
double
tscgetf(void)
{
    struct timespec ts;
    double sec;

    clock_gettime(CLOCK_MONOTONIC,&ts);

    sec = ts.tv_nsec;
    sec /= 1e9;
    sec += ts.tv_sec;

    return sec;
}

// genlength -- generate all words of a given length from all chars in charset
void
genlength(FILE *file,const char *charset,int iwid)
{
    int charset_length = strlen(charset);
    unsigned long long wordcount = 0;

    char buffer[iwid + 1];

    // create a number in base(charset_length) with iwid number of digits
    unsigned char bignum[iwid];
    memset(bignum,0,iwid);

    // show some progress
    printf("genlength: iwid=%d\n",iwid);

    double tscold = tscgetf();

    while (1) {
        // get the current output word
        for (int idx = 0;  idx < iwid;  ++idx)
            buffer[idx] = charset[bignum[idx]];
        buffer[iwid] = 0;

        // send it to the file
        fputs(buffer,file);
        fputc('\n',file);

        // advance the base(charset_length) number
        if (incbignum(bignum,iwid,charset_length))
            break;

        // show progress
        if ((++wordcount % 3761) == 0) {
            double tscnow = tscgetf();
            if ((tscnow - tscold) >= 1.0) {
                printf("\rwordcount=%llu %s",wordcount,buffer);
                fflush(stdout);
                tscold = tscnow;
            }
        }
    }

    printf("\nfinal=%llu\n",wordcount);
}

void
Dictionary_Generator(const char *charset, int min, int max)
{
    char *password = malloc((max + 1) * sizeof(char));

    if (password == NULL) {
        fprintf(stderr, "Error: memory allocation failed\n");
        exit(1);
    }

    FILE *file = fopen("dictionary.txt", "w");

    if (file == NULL) {
        fprintf(stderr, "Error: could not create file\n");
        exit(1);
    }

    int charset_length = strlen(charset);
#if 0
    int num_combinations = pow(charset_length, max);
#else
    int num_combinations = pow(charset_length, max - min);
#endif
    printf("num_combinations=%d\n",num_combinations);

#if 0
    for (int i = 0; i < num_combinations; i++) {
        int index = i;
        int length = min;

        while (index >= charset_length) {
            password[length - 1] = charset[index % charset_length];
            index /= charset_length;
            length++;
        }
        password[length - 1] = charset[index];
        password[length] = '\0';
        if (length >= min) {
            int result = fprintf(file, "%s\n", password);

            if (result < 0) {
                perror("Error writing to file");
                exit(1);
            }
        }
    }
#else
    for (int iwid = min;  iwid <= max;  ++iwid)
        genlength(file,charset,iwid);
#endif

    fclose(file);
    free(password);
}

int
main()
{
// NOTE -- the full charset takes a _long_ time ... :-)
#if TEST
    const char *charset = "abcdefghijklmnopqrstuvwxyz";
#else
    const char *charset = "abcdefghijklmnopqrstuvwxyz"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789";
#endif
    int min = 4;
    int max = 8;

    Dictionary_Generator(charset, min, max);

    return 0;
}
Craig Estey
  • 30,627
  • 4
  • 24
  • 48