Пароль не будет зашифрован должным образом (содержит слишком много символов)

0

Я пишу программу паролей. Программа начинается с запроса пользователя ввести пароль, который включает в себя 8 или более символов, которые включают символ и знаки препинания.

После этого программа "зашифрует" пароль, переместив вторую половину пароля на передний, добавив "+" в середине, а затем добавив первую половину до конца.

Проблема, которую я получаю, заключается в том, что всякий раз, когда я ввожу пароль с нечетными символами, он копирует последний символ дважды и нарушает мою программу. Как это исправить? Я знаю, что мне нужно добавить условие, если есть нечетные символы, но idk, что он должен включить. Вот мой код:

// write a function to encrypt the password:
// return a dynamically allocated C string of the exact size (no extra room) with:
// the last half of the password, the + symbol, and then the first half of the password
char * encrypt (char pw[])
 {
int exactsize = strlen(pw) + 2;
char * encPW = new char[exactsize];
int mid = exactsize / 2;


strcpy(encPW, pw + mid);
strcat(encPW, "+");
strncat(encPW, pw, exactsize - mid);

return encPW;

 }

 // write the same (overloaded) function for a C++ String
 char * encrypt (string pw)
 {
int exactsize = pw.length() + 2;
char * encPW = new char[exactsize];
int mid = exactsize / 2;

string temp(pw, mid);
string temp2(pw, 0 ,mid);
temp = temp + "+" + temp2;

strcpy(encPW, temp.c_str());


return encPW;
}

here is the output i am getting and what i am talking about:
Enter your password: salehrocks93
add punctuation
Enter your password: salehrocks93/
Valid password format. Encrypting...

Encrypted password: cks93/+salehroc

Enter your new password: salehrocks93/
New Encrypted password: cks93/+salehro
1
Press any key to continue . . .

когда он запрашивает пароль в первый раз и шифрует его, c повторяется дважды

  • 0
    Какое поведение требуется, когда пароль имеет нечетную длину? Например, каким должно быть шифрование «паролей»?
  • 0
    Несколько наблюдений без ответов: 1. Ваш API не сбалансирован: функция выделяет память, но требует, чтобы вызывающий ее освободил - это плохая практика. 2. Ваша перегрузка принимает значение std::string по значению - это означает, что она создает локальную копию при вызове, что делает ее перегрузку плохим выбором дизайна. Сделайте это const std::string& чтобы взять его по ссылке. 3. temp = temp + "+" + temp2; думать о том, что это делает ...
Показать ещё 2 комментария
Теги:
string
encryption
c-strings

2 ответа

1
Лучший ответ

Что мне нравится делать с такими проблемами? Пройдите через них. Я нахожу, что это часто помогает разобраться. Хорошая ручка и отладка бумаги. Если вы не можете понять это на бумаге, как вы поймете это на компьютере?! Есть так много проводов!

Так. Пусть пройдет через него. Сначала нам нужно выбрать поддельный аргумент, чтобы передать его.


В целях этой демонстрации позвольте использовать строку C-style, NULL-terminated "PASSWOR". Если бы я рисовал этот массив, это могло бы выглядеть так:

['P'].['A'].['S'].['S'].['W'].['O'].['R']

Хорошо, теперь на ваш код.

char * encrypt (char pw[])
 {
  int exactsize = strlen(pw) + 2;
  char * encPW = new char[exactsize];
  int mid = exactsize / 2;

Здесь мы находимся в начале вашей функции. Вы указали переменную точный размер, используя длину строки и магическое число. Я предполагаю, что вы используете этот магический номер для учета терминатора NULL и "+", который вы хотите добавить.

Итак, с нашим поддельным аргументом "ПАРОЛЬ", мы должны получить strlen() из 7, что сделает наш "точный" 9.

Затем вы выделяете массив символов, encPW, как новый "точный" размер. Вот как выглядит теперь encPW, как массив символов

// initial value
[ 0 ].[ 0 ].[ 0 ].[ 0 ].[ 0 ].[ 0 ].[ 0 ].[ 0 ].[ 0 ]
// with indices
  0     1     2     3     4     5     6     7     8

Затем вы объявляете середину, которую, я думаю, мы можем смело считать серединой. Это немного сложно, потому что вы определяете середину в отношении вашего нового размера. Но пусть придерживаться кода под рукой. Поскольку наш точный размер равен 9, тогда средний уровень должен быть 4,5. Но это целое число, поэтому конечный результат равен 4. Мы продолжаем.

strcpy(encPW, pw + mid);

Теперь вы входите в пункт назначения encPW, начиная с pw + mid. pw + mid дает нам указатель на символ W из исходной строки. Он будет копировать до и включать терминатор NULL.

// now what do we have?
['W'].['O'].['R'].[ 0 ].[ 0 ].[ 0 ].[ 0 ].[ 0 ].[ 0 ]

Затем вы добавляете "+" к строке:

strcat(encPW, "+");
// now what do we have?
[ 'W' ].[ 'O' ].[ 'R' ].[ '+' ].[ 0 ].[ 0 ].[ 0 ].[ 0 ].[ 0 ]

Наконец, вы вызываете strncat(), который добавляет num символов в строку C-стиля, плюс NULL-терминатор.

Вы говорите ему, чтобы писать exactsize - mid символы в строку. Так как exactsize равно 9, а середина - 4, мы говорим ему писать 5 символов.

Как мы видели выше, strncat также пишет NULL-терминатор. Это 6 символов! Однако, как мы можем видеть (подсчитав 0 слева в строке выше), осталось только 5 символов, прежде чем мы записываем в память, которая не наша!

Вот что происходит под капотом (на высоком уровне)

strncat(encPW, pw, exactsize - mid)
// strncat tries to write this stuff at the end
[ 'W' ].[ 'O' ].[ 'R' ].[ '+' ].[ 'P' ].[ 'A' ].[ 'S' ].[ 'S' ].[ 'W' ].[ 0 ]
                                                                         .^
                                      Uh oh, somebody call the memory police!

Однако, даже если мы не писали в страшную, загадочную память, алгоритм все еще кажется принципиально ошибочным, потому что один из наших персонажей появляется дважды!


Мой вопрос для вас: что такое середина? Как вы намеревались использовать его, когда вы его объявили?

Итак, теперь мы придумали простую ручку и бумагу.


Как бы я решил это:

int mid = strlen(pw) / 2;

И для вашего strncat() я бы использовал

strncat(encPW, pw, mid)

Это решает несколько проблем для нас. Позвольте использовать два примера: "ПАРОЛЬ" и "ПАРОЛЬ".

Используя "ПАРОЛЬ", середина будет 3

pw + mid будет "S" (второй)

После того, как strcpy encPW будет "SWOR",

После первого strcat это будет "SWOR+"

После strncat(encPW, pw, mid) это будет "SWOR+ PAS".

Идеально, да?

Используя "ПАРОЛЬ", средний будет 4

pw + mid будет "W"

После того как strcpy encPW будет "WORD"

После первого strcat это будет "WORD+"

После strncat(encPW, pw, mid) это будет "WORD+ PASS".

0
#include <iostream>
#include <string>

void encrypt(const std::string& password)
{
    size_t exactSize = password.length() + sizeof('+') + sizeof('\0');
    size_t mid = exactSize / 2;

    std::cout << "password = " << password
              << ", exactSize = " << exactSize
              << ", mid = " << mid
              << ", password[0,mid) = " << password.substr(0, mid)
              << ", password[mid,npos) = " << password.substr(mid, std::string::npos)
              << '\n';

    std::string t1(password, mid);
    std::string t2(password, 0, mid);

    std::cout << "t1 = " << t1 << ", t2 = " << t2 << '\n';
}

int main()
{
    encrypt("12345678");
    encrypt("123456789");

    return 0;
}

Производит вывод http://ideone.com/fork/Y9GsHM

password = 12345678,  exactSize = 10, mid = 5, password[0,mid) = 12345, password[mid,npos) = 678
t1 = 678, t2 = 12345
password = 123456789, exactSize = 11, mid = 5, password[0,mid) = 12345, password[mid,npos) = 6789
t1 = 6789, t2 = 12345

Проблема в том, что exactSize - это размер результата, включая "+" и "\ 0", а не размер исходной строки.

#include <iostream>
#include <string>

void encrypt(const std::string& password)
{
    size_t mid = password.length() / 2;
    size_t exactSize = password.length() + sizeof('+') + sizeof('\0');

    std::cout << "password = " << password
              << ", exactSize = " << exactSize
              << ", mid = " << mid
              << ", password[0,mid) = " << password.substr(0, mid)
              << ", password[mid,npos) = " << password.substr(mid, std::string::npos)
              << '\n';

    std::string t1(password, mid);
    std::string t2(password, 0, mid);

    std::cout << "t1 = " << t1 << ", t2 = " << t2 << '\n';
}

int main()
{
    encrypt("12345678");
    encrypt("123456789");

    return 0;
}

http://ideone.com/E5YFKm

Ваша версия C-строки довольно изворотливая, я сделал соответствующую C-строчную версию вышеуказанного кода.

#include <iostream>
#include <cstring>

void encrypt(const char* password)
{
    size_t len = strlen(password);
    size_t allocSize = strlen(password) + sizeof('+') + sizeof('\0');
    size_t mid = len / 2;

    char left[16];
    char right[16];

    strncpy(left, password, len - mid);
    left[len - mid] = '\0';
    strcpy(right, password + mid);

    std::cout << "password = " << password
              << ", len = " << len
              << ", remainder = " << (len - mid)
              << ", mid = " << mid
              << ", left = " << left
              << ", right = " << right
              << '\n';
}

int main()
{
    std::cout << "begin\n";
    encrypt("12345678");
    encrypt("123456789");

    return 0;
}

http://ideone.com/O6Na9t

Ещё вопросы

Сообщество Overcoder
Наверх
Меню