Browse Source

feat: 初步实现H-Password的功能

支持生成标签
支持从标签获取账户信息
SongZihuan 3 years ago
commit
08638497de
9 changed files with 752 additions and 0 deletions
  1. 59 0
      .gitignore
  2. 7 0
      CMakeLists.txt
  3. 19 0
      README.md
  4. 179 0
      argument.c
  5. 23 0
      argument.h
  6. 118 0
      base64.c
  7. 185 0
      main.c
  8. 30 0
      main.h
  9. 132 0
      passwd.c

+ 59 - 0
.gitignore

@@ -0,0 +1,59 @@
+# C Language
+# Prerequisites
+*.d
+
+# Object files
+*.o
+*.ko
+*.obj
+*.elf
+
+# Linker output
+*.ilk
+*.map
+*.exp
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Libraries
+*.lib
+*.a
+*.la
+*.lo
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+*.i*86
+*.x86_64
+*.hex
+
+# Debug files
+*.dSYM/
+*.su
+*.idb
+*.pdb
+
+# Kernel Module Compile Results
+*.mod*
+*.cmd
+.tmp_versions/
+modules.order
+Module.symvers
+Mkfile.old
+dkms.conf
+
+#IDE
+.idea
+.vs
+.vscode
+cmake-*

+ 7 - 0
CMakeLists.txt

@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 3.16)
+project(H_Passwd C)
+
+set(CMAKE_C_STANDARD 11)
+
+add_definitions(-DVERSION="0.0.1" -DVERSION_INFO="H-Password, now start.")
+add_executable(H_Passwd main.c base64.c passwd.c argument.c)

+ 19 - 0
README.md

@@ -0,0 +1,19 @@
+# H-Password 密码管理软件
+
+## 简介
+H-Password可以帮助你更快的管理密码。通常,我们习惯将密码记录到本子或电脑上以防止忘记。但是名文记录的密码总是难免会泄露。
+因此,我们可以使用H-Password管理密码。你只需要自定义并且记住一个密钥到脑子中即可。H-Passwd会根据你的密钥和账户信息生成
+一个无规则的标签文本。你可以将该便签文本直接记录在任何地方,不用担心被人看见。当你需要寻找密码的时候,只需要启动H-Password
+然后输入你的密钥和对应的标签即可获得相应的账号信息。  
+你的账号信息不会被H-Password存储在然和地方,包括你的电脑和云端。H-Password通过计算获取账号信息。
+
+## 命令行参数
+```
+Usage: E:\CProject\H-Passwd\cmake-build-debug\H_Passwd.exe <[option]..>
+Option:
+ -v --version       显示当前版本信息。
+ -h --help          显示帮助文档。
+ -s --set-pw        根据密钥和账户信息生成一个标签文本。
+ -g --get-pw        根据密钥和标签文本获取账户信息。
+```
+

+ 179 - 0
argument.c

@@ -0,0 +1,179 @@
+#include "argument.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+
+int opt_i = 0;
+int opt_flat = 0;
+char *opt_val = NULL;
+int argc_ = 0;
+char **argv_ = NULL;
+
+struct arg_define *arg_;
+
+enum {
+    normal = 0,
+    at_end,
+    continue_flat,  // 如处理-abc这样连续的短选项
+} status;
+
+int continue_index = 0;
+bool exchange_one = false;  // 只发生了一次exchange, 意味着新arg的下一个arg与该arg并非连接的关系
+// 如: zz -s -y -> -s zz -y,显然-s与zz并非连接关系
+
+bool initOpt(bool base, int argc, char **argv, struct arg_define *arg) {
+    if (base)
+        opt_i = 1;
+    else
+        opt_i = 0;
+
+    argc_ = argc;
+    argv_ = argv;
+    arg_ = arg;
+    opt_flat = 0;
+    opt_val = NULL;
+    status = normal;
+    return argc_ != 0 && arg != NULL;
+}
+
+static int getReturn(struct arg_define *arg) {
+    switch (arg->argument) {
+        case no_argument:
+            return arg->flat;
+        case can_argument:
+            if (!exchange_one && (status != continue_flat || argv_[opt_i][continue_index + 1] == '\0') && opt_i + 1 < argc_) {
+                opt_val = argv_[opt_i + 1];
+            } else
+                opt_val = NULL;
+            return arg->flat;
+        case must_argument:
+            if (!exchange_one && (status != continue_flat && argv_[opt_i][continue_index + 1] == '\0') || opt_i + 1 >= argc_) {
+                fprintf(stderr, "-%c --%s : Lack of argument.\n", arg->ch, arg->name);
+                return '?';
+            }
+            opt_val = argv_[opt_i + 1];
+            return arg->flat;
+    }
+
+    fprintf(stderr, "%s : Error argument.\n", argv_[opt_i]);
+    return '?';
+}
+
+static int getShort(char ch) {
+    struct arg_define *arg = arg_;
+    while (arg->ch != 0) {
+        if (arg->ch != '?' && arg->ch == ch)
+            return getReturn(arg);
+        arg++;
+    }
+
+    fprintf(stderr, "-%c : Don't support argument.\n", ch);
+    return '?';
+}
+
+static int getLong(char *name) {
+    struct arg_define *arg = arg_;
+    while (arg->ch != 0) {
+        if (arg->name != NULL && !strcmp(arg->name, name))
+            return getReturn(arg);
+        arg++;
+    }
+
+    fprintf(stderr, "--%s : Don't support argument.\n", name);
+    return '?';
+}
+
+static int getOpt_(void) {
+    if (status == at_end)
+        return 0;
+
+    if (status == continue_flat) {
+        if (argv_[opt_i][continue_index] == '\0') {
+            opt_i ++;
+            status = normal;
+            continue_index = 0;
+        } else {
+            int re = getShort(argv_[opt_i][continue_index]);
+            if (opt_val != NULL) {
+                opt_i += 2;
+                status = normal;
+                continue_index = 0;
+            } else
+                continue_index++;
+            return re;
+        }
+    }
+
+    if (opt_i >= argc_) {
+        status = at_end;
+        return 0;
+    }
+
+    if (!strcmp(argv_[opt_i], "--")) {  // 后面的参数全部当作非选项处理
+        opt_i++;
+        status = at_end;
+        return 0;
+    }
+
+    if (strlen(argv_[opt_i]) < 2 || argv_[opt_i][0] != '-') {  // 如果是短选型起码是-a两个字符,如果是长选项必然--开头也大于两个字符
+        for (int i = opt_i + 1; i < argc_; i++) {
+            if (!strcmp(argv_[i], "--"))
+                break;
+            if (argv_[i][0] == '-') {  // 交换
+                if (i + 1 < argc_ && argv_[i + 1][0] != '-') {  // argv_[i + 1]可能是参数, 若不是参数移动他也没有关系
+                    char *tmp1 = argv_[i];
+                    char *tmp2 = argv_[i + 1];
+                    memmove(argv_ + opt_i + 2, argv_ + opt_i, (i - opt_i) * sizeof(char *));
+                    argv_[opt_i] = tmp1;
+                    argv_[opt_i + 1] = tmp2;
+                } else {
+                    char *tmp = argv_[i];
+                    memmove(argv_ + opt_i + 1, argv_ + opt_i, (i - opt_i) * sizeof(char *));
+                    argv_[opt_i] = tmp;
+                    exchange_one = true;
+                }
+
+                goto continue_;
+            }
+        }
+
+        // 寻找无果
+        // opt_i不用增加1, 当前和后面的参数全部当作非选项处理
+        status = at_end;
+        return 0;
+    }
+
+    continue_:
+    if (argv_[opt_i][0] == '-' && argv_[opt_i][1] != '-') {
+        status = continue_flat;
+        continue_index = 1;
+        int re = getShort(argv_[opt_i][1]);
+        if (opt_val != NULL) {
+            opt_i += 2;
+            status = normal;
+        } else
+            continue_index = 2;
+        return re;
+    }
+
+    if (argv_[opt_i][0] == '-' && argv_[opt_i][1] == '-') {
+        int re = getLong(argv_[opt_i] + 2);
+        if (opt_val != NULL)
+            opt_i += 2;
+        else
+            opt_i++;
+        return re;
+    }
+
+    fprintf(stderr, "%s : Not support argument.\n", argv_[opt_i]);
+    opt_i++;
+    return '?';  // 理论上不应该会运算到这里
+}
+
+int getOpt(void) {
+    exchange_one = false;
+    opt_val = NULL;
+    opt_flat = getOpt_();
+    return opt_flat;
+}

+ 23 - 0
argument.h

@@ -0,0 +1,23 @@
+#ifndef H_PASSWD_ARGUMENT_H
+#define H_PASSWD_ARGUMENT_H
+#include <stdbool.h>
+
+extern int opt_i;
+extern int opt_flat;
+extern char *opt_val;
+
+struct arg_define {
+    char ch;
+    char *name;
+    int flat;
+    enum {
+        no_argument,
+        can_argument,
+        must_argument,
+    } argument;
+};
+
+int getOpt(void);
+bool initOpt(bool base, int argc, char **argv, struct arg_define *arg);
+
+#endif //H_PASSWD_ARGUMENT_H

+ 118 - 0
base64.c

@@ -0,0 +1,118 @@
+#include "main.h"
+
+//定义base64编码表
+static char *base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";  // base-64的基础编码 + 等号
+static char base64_table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static unsigned char table_base64[128] = {0};
+static char fill = '=';  // 默认填充字符
+
+void initBase64(char *_key) {  // 生成编码序列
+    int count = 0;
+
+    if (strlen(_key) > 0) {
+        char *key = base64Encode(_key);  // 先按基础base64编码
+        size_t key_len = strlen(key);
+        fill = key[0];
+
+        memset(base64_table, 0, 64);
+        for (int i = 1; i < key_len; i++) {  // 跳过第一个字符
+            if (key[i] != fill && strchr(base64_table, key[i]) == NULL) {
+                base64_table[count] = key[i];
+                count++;
+            }
+        }
+
+        free(key);
+    }
+
+    for (int i = 0; count < 64; i++) {  // 填充base的内容
+        if (base[i] != fill && strchr(base64_table, base[i]) == NULL) {
+            base64_table[count] = base[i];
+            count++;
+        }
+    }
+
+    for (int i = 0; i < 64; i++)
+        table_base64[base64_table[i]] = i;
+
+}
+
+char *base64Encode(char *str) {
+    size_t len;
+    size_t str_len;
+    size_t str_len_3;
+    char *res;
+
+    str_len = strlen(str);
+    str_len_3 = (str_len / 3) * 3;
+
+    if(str_len % 3 == 0)
+        len = str_len / 3 * 4;  // 每三个char共3 * 8 = 24(bit),用4个char来表示(这4个char其实只用了 6 bit)
+    else
+        len = (str_len / 3 + 1) * 4;
+
+    res = calloc(len + 1, sizeof(char));
+
+    for(int i = 0, j = 0; j < str_len_3; j += 3, i += 4)  // i是res索引, j是str索引
+    {
+        res[i + 0] = base64_table[(unsigned)str[j] >> 2];
+        res[i + 1] = base64_table[(unsigned)(str[j] & 0x03) << 4 | (unsigned)(str[j + 1] >> 4)];
+        res[i + 2] = base64_table[(unsigned)(str[j + 1] & 0x0f) << 2 | (unsigned)(str[j + 2] >> 6)];
+        res[i + 3] = base64_table[(unsigned)str[j + 2] & 0x3f];
+    }
+
+    switch(str_len % 3)
+    {
+        case 1:
+            res[len - 4] = base64_table[(unsigned)str[str_len_3] >> 2];
+            res[len - 3] = base64_table[(unsigned)(str[str_len_3]&0x3) << 4];
+            res[len - 2] = fill;
+            res[len - 1] = fill;
+            break;
+        case 2:
+            res[len - 4] = base64_table[(unsigned)str[str_len_3] >> 2];
+            res[len - 3] = base64_table[(unsigned)(str[str_len_3] & 0x3) << 4 | (unsigned)(str[str_len_3 + 1] >> 4)];
+            res[len - 2] = base64_table[(unsigned)(str[str_len_3 + 1] & 0xf) << 2];
+            res[len - 1] = fill;
+            break;
+        default:
+            break;
+    }
+
+    return res;
+}
+
+
+unsigned int base64ToASCII(char ascii) {
+    char *p = strchr(base64_table, (int)ascii);
+    if (p == NULL)
+        exit(EXIT_FAILURE);
+
+    return p - base64_table;
+}
+
+
+char *base64Decode(char *code) {
+    size_t len;
+    size_t str_len;
+    char *res;
+    int i, j;
+
+    len = strlen(code);
+    str_len = len / 4 * 3;
+    if (code[len - 1] == fill) {
+        str_len--;
+        if (code[len - 2] == fill)
+            str_len--;
+    }
+
+    res = calloc(str_len + 1, sizeof(char));
+
+    for (i = 0, j = 0; i < len - 2; j += 3, i += 4) {
+        res[j] = table_base64[code[i]] << 2 | (table_base64[code[i + 1]] >> 4);
+        res[j + 1] = (table_base64[code[i + 1]] << 4) | (table_base64[code[i + 2]] >> 2);
+        res[j + 2] = (table_base64[code[i + 2]] << 6) | (table_base64[code[i + 3]]);
+    }
+
+    return res;
+}

+ 185 - 0
main.c

@@ -0,0 +1,185 @@
+#include "main.h"
+#include "argument.h"
+#include <stdio.h>
+
+char *key = NULL;
+char *name = NULL;
+struct arg_define arg[] = {
+        {.ch='v', .name="version", .flat='v', .argument=no_argument},
+        {.ch='h', .name="help", .flat='h', .argument=no_argument},
+        {.ch='s', .name="set-pw", .flat='s', .argument=no_argument},
+        {.ch='g', .name="get-pw", .flat='g', .argument=no_argument},
+        {.ch=0},
+};
+enum {
+    no = 0,
+    set_pw,
+    get_pw,
+} work = no;
+
+void printVersion(void);
+void printHelp(void);
+bool setPassWd(void);
+bool getPassWd(void);
+
+int main(int argc, char **argv) {
+    name = argv[0];
+    initOpt(true, argc, argv, arg);
+
+    for (getOpt(); opt_flat != 0; getOpt()) {
+        switch (opt_flat) {
+            case 'h':
+                printHelp();
+                exit(EXIT_SUCCESS);
+            case 'v':
+                printVersion();
+                exit(EXIT_SUCCESS);
+            case 's':
+                if (work != no)
+                    exit(EXIT_FAILURE);
+                work = set_pw;
+                break;
+            case 'g':
+                if (work != no)
+                    exit(EXIT_FAILURE);
+                work = get_pw;
+                break;
+            case 0:
+                break;
+            case '?':
+            default:
+                exit(EXIT_FAILURE);
+        }
+    }
+
+    if (work == no) {
+        fprintf(stderr, "What should I do?\n");
+        printHelp();
+        exit(EXIT_FAILURE);
+    }
+
+    if (argc - opt_i > 1)
+        exit(EXIT_FAILURE);
+    else if (argc - opt_i == 1) {
+        if (key != NULL)
+            exit(EXIT_FAILURE);
+        key = calloc(strlen(argv[opt_i]) + 1, sizeof(char ));
+        strcpy(key, argv[opt_i]);
+        opt_i++;
+    } else if (key == NULL) {
+        printf("Please Enter The Key:\n");
+        key = calloc(KEY_MAX_LEN + 10, sizeof(char ));
+        fgets(key, KEY_MAX_LEN + 10, stdin);
+        if (strchr(key, '\n') == NULL) {
+            fprintf(stderr, "Key too long for stdin.\n");
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    if (!isLegalKey(key))
+        exit(EXIT_FAILURE);
+    initBase64(key);
+
+    bool status = false;
+    if (work == set_pw)
+        status = setPassWd();
+    else
+        status = getPassWd();
+
+    if (!status)
+        return EXIT_FAILURE;
+    return EXIT_SUCCESS;
+}
+
+void printVersion(void) {
+    printf("%s Version:\n%s\n%s\n", name, VERSION, VERSION_INFO);
+}
+
+void printHelp(void) {
+    printf("Usage: %s <[option]..>\n", name);
+    printf("Option: \n");
+    printf(" -v --version       Show version.\n");
+    printf(" -h --help          Show help.\n");
+    printf(" -s --set-pw        Set Password.\n");
+    printf(" -g --get-pw        Get Password.\n\n");
+
+    printf("How to use?\n");
+    printf( "     You can choose a key and remember it. \n"
+           "With set-pw, a tag is generated after you \n"
+           "enter your key and the account information \n"
+           "you want to store. Using get-pw, you can enter \n"
+           "your own key and label to obtain the stored \n"
+           "account information.\n"
+           "     Account information includes the account, \n"
+           "password, and remarks. The account and password \n"
+           "can only be visible non-whitespace characters. \n"
+           "Remarks Can be visible non-whitespace characters \n"
+           "and Spaces. All three must be set and the total \n"
+           "length must not exceed 100.\n\n");
+
+    printf("Length limit:\n");
+    printf("Key: [%d - %d]\n\n", KEY_MIN_LEN, KEY_MAX_LEN);
+
+    printf("Name origin:\n");
+    printf("I'm super Huan. H in h-password is Huan in superhuan. \n"
+           "Password means that the software is password software.\n\n");
+
+}
+
+#define READ_WORD(key, len, key_name, re) do { printf("Please Enter The " key_name ":\n"); \
+    (key) = calloc((len) + 10, sizeof(char )); \
+    fgets((key), (len) + 10, stdin); \
+    if (strchr((key), '\n') == NULL) { \
+        fprintf(stderr, key_name " too long for stdin.\n"); \
+        goto re; \
+    } else {*strchr((key), '\n') = 0;} \
+    }while(0)
+
+bool setPassWd(void) {
+    char *account;
+    char *passwd;
+    char *note;
+    char *passwd_str;
+
+    READ_WORD(account, 100, "Your account", ERROR1);
+    READ_WORD(passwd, 100, "Your password", ERROR2);
+    READ_WORD(note, 100, "Your note", ERROR3);
+
+    passwd_str = makePasswordString(account, passwd, note);
+    if (passwd_str == NULL)
+        goto ERROR4;
+    printPasswdStr(account, passwd, note, passwd_str);
+
+    free(account);
+    free(passwd);
+    free(note);
+    free(passwd_str);
+    return true;
+
+    ERROR4: free(note);
+    ERROR3: free(passwd);
+    ERROR2: free(account);
+    ERROR1: return false;
+}
+
+bool getPassWd(void) {
+    char *account;
+    char *passwd;
+    char *note;
+    char *passwd_str;
+
+    READ_WORD(passwd_str, 200, "Your Label", ERROR1);
+
+    if (!getInfoFromPasswordString(passwd_str, &account, &passwd, &note))
+        goto ERROR2;
+    printInfo(account, passwd, note);
+
+    free(account);
+    free(passwd);
+    free(note);
+    free(passwd_str);
+    return true;
+
+    ERROR2: free(passwd_str);
+    ERROR1: return false;
+}

+ 30 - 0
main.h

@@ -0,0 +1,30 @@
+#ifndef H_PASSWD_MAIN_H
+#define H_PASSWD_MAIN_H
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef KEY_MAX_LEN
+#define KEY_MAX_LEN (60) /* 密钥最大长度 */
+#endif
+
+#ifndef KEY_MIN_LEN
+#define KEY_MIN_LEN (10) /* 密钥最短长度 */
+#endif
+
+#ifndef VERSION
+#define VERSION "Special version."
+#define VERSION_INFO "Special characters, special uses."
+#endif
+
+char *base64Encode(char *str);
+char *base64Decode(char *code);
+void initBase64(char *key);
+
+bool isLegalKey(char *key);
+char *makePasswordString(char *account, char *passwd, char *note);
+bool getInfoFromPasswordString(char *passwd_base64, char **account, char **passwd, char **note);
+void printInfo(char *account, char *passwd, char *note);
+void printPasswdStr(char *account, char *passwd, char *note, char *passwd_str);
+
+#endif //H_PASSWD_MAIN_H

+ 132 - 0
passwd.c

@@ -0,0 +1,132 @@
+#include "main.h"
+
+#include <ctype.h>
+#include <stdio.h>
+
+#define CHECK_PRINT(key, key_len, re, info) do{ for (int i = 0; i < (key_len); i++) { \
+    if (!isprint((key)[i]) || isspace((key)[i])) { \
+        fprintf(stderr, info " (at %d is %d).\n", i, (key)[i]); \
+        return (re); \
+    } \
+}}while(0)
+
+bool isLegalKey(char *key) {  // 判断是否为合法的密钥
+    size_t key_len = strlen(key);
+    if (key_len > KEY_MAX_LEN) {
+        fprintf(stderr, "Key too long (> %d).\n", KEY_MAX_LEN);
+        return false;
+    }
+
+    if (key_len < KEY_MIN_LEN) {
+        fprintf(stderr, "Key too short (< %d).\n", KEY_MIN_LEN);
+        return false;
+    }
+
+    CHECK_PRINT(key, key_len, false, "The key does not allow invisible characters");  // 检查是否可读可打印
+    return true;
+}
+
+#define CHECK_STRLEN(key, re, info) do{ if ((key) == 0) { \
+    fprintf(stderr, info "\n"); \
+    return (re); \
+}}while(0)
+
+static char *makePasswordString_(char *account, char *passwd, char *note) {
+    char *passwd_str;
+    size_t account_len = strlen(account);
+    size_t passwd_len = strlen(passwd);
+    size_t note_len = strlen(note);
+    size_t str_len = (account_len + passwd_len + note_len + 4);  // 4个标记长度
+
+    CHECK_STRLEN(account_len, NULL, "Account must be entered.");
+    CHECK_STRLEN(passwd_len, NULL, "Password must be entered.");
+    CHECK_STRLEN(note_len, NULL, "Note must be entered.");
+
+    if (str_len > 100) {  // 太大了char会放不下
+        fprintf(stderr, "Account or passwd or note too long (The sum is greater than 100).\n");
+        return NULL;
+    }
+
+    CHECK_PRINT(account, account_len, NULL, "Account contains illegal characters");
+    CHECK_PRINT(passwd, passwd_len, NULL, "Passwd contains illegal characters");
+
+    for (int i = 0; i < note_len; i++) {
+        if (!isprint(note[i]) || (isspace(note[i]) && note[i] != ' ')) {  // 允许为空格
+            fprintf(stderr, "Note contains illegal characters (at %d is %d).\n", i, note[i]);
+            return NULL;
+        }
+    }
+
+    passwd_str = calloc(str_len + 1, sizeof(char));
+    passwd_str[0] = (char)str_len;
+    passwd_str[1] = (char)account_len;
+    passwd_str[2] = (char)passwd_len;
+    passwd_str[3] = (char)note_len;
+    strcpy(passwd_str + 4, account);
+    strcpy(passwd_str + 4 + account_len, passwd);
+    strcpy(passwd_str + 4 + account_len + passwd_len, note);
+
+    return passwd_str;
+}
+
+char *makePasswordString(char *account, char *passwd, char *note){
+    char *passwd_str = makePasswordString_(account, passwd, note);
+    if (passwd_str == NULL)
+        return NULL;
+
+    char *base64 = base64Encode(passwd_str);
+    free(passwd_str);
+    return base64;
+}
+
+static bool getInfoFromPasswordString_(char *passwd_str, char **account, char **passwd, char **note) {
+    size_t passwd_str_len = strlen(passwd_str);
+
+    if (passwd_str_len < 4) {
+        fprintf(stderr, "Key or label error.\n");
+        return false;
+    }
+
+    size_t account_len = (size_t)passwd_str[1];
+    size_t passwd_len = (size_t)passwd_str[2];
+    size_t note_len = (size_t)passwd_str[3];
+    size_t str_len = (size_t)passwd_str[0];
+
+    if (passwd_str_len != str_len) {
+        fprintf(stderr, "Key or label error.\n");
+        return false;
+    }
+
+    *account = calloc(account_len + 1, sizeof(char ));
+    *passwd = calloc(passwd_len + 1, sizeof(char ));
+    *note = calloc(note_len + 1, sizeof(char ));
+    memcpy(*account, passwd_str + 4, account_len);
+    memcpy(*passwd, passwd_str + 4 + account_len, passwd_len);
+    memcpy(*note, passwd_str + 4 + account_len + passwd_len, note_len);
+
+    return true;
+}
+
+bool getInfoFromPasswordString(char *passwd_base64, char **account, char **passwd, char **note) {
+    char *passwd_str = base64Decode(passwd_base64);
+    bool re = getInfoFromPasswordString_(passwd_str, account, passwd, note);
+    free(passwd_str);
+    return re;
+}
+
+void printInfo(char *account, char *passwd, char *note) {
+    printf("Account Information Print\n");
+    printf("Account: '%s'\n", account);
+    printf("Password: '%s'\n", passwd);
+    printf("Note: '%s'\n", note);
+    printf("H-Passwd: So that the password will not be forgotten.");
+}
+
+void printPasswdStr(char *account, char *passwd, char *note, char *passwd_str) {
+    printf("Account Information Print\n");
+    printf("Account: '%s'\n", account);
+    printf("Password: '%s'\n", passwd);
+    printf("Note: '%s'\n", note);
+    printf("Label: '%s'\n", passwd_str);
+    printf("You can retrieve account information via label and key. (Include Account, Password and Note.)");
+}