在Windows和Linux系统上,用C语言实现命令行下输入密码回显星号和完全隐藏密码

news2024/11/18 3:05:19

本篇目录

  • 引子
  • 在Windows 上实现
  • 在Linux上实现
    • 回显星号
      • 代码解读
      • 运行
    • 完全隐藏
      • 运行

引子

在Windows系统上,当我们使用命令行和MySQL进行交互时,第一步就是要输入密码:

在这里插入图片描述

-p后面的参数紧跟着的就是相应用户的密码。然而这种方式并不安全,因为密码是以明文的方式直接显示在命令行的,如果有人通过特定方式,刻意查看命令行的日志记录,就会查看到这条命令,后面的密码也会随之暴露。所以以这种方式登录到数据库,会弹出一条警告:mysql: [Warning] Using a password on the command line interface can be insecure.
在这里插入图片描述

较为安全的方式为:
在这里插入图片描述
这里我们会看到,密码在输入的时候是用星号代替的,将密码隐藏起来。这是为了提高安全性。


在Windows 上实现

下面给出C语言代码,来实现隐藏密码的功能:

#include <stdio.h>
#include <conio.h>

#define MAX_PASSWORD_LENGTH 20   //密码最大长度

int main()
{
    char password[MAX_PASSWORD_LENGTH];
    int i = 0;
    char ch;

    printf("Enter your password: ");

    while (1)
    {
        ch = getch();     //接收一个字符

        if (ch == 13) // If Enter key is pressed    回车键的ASCII值为13
            break;
        else if (ch == 8) // If Backspace key is pressed
        {
            if (i > 0)
            {
                printf("\b \b");
                i--;
            }
        }
        else if (ch != ' ' && i < MAX_PASSWORD_LENGTH - 1)
        {
            printf("*");
            password[i] = ch;
            i++;
        }
    }

    password[i] = '\0'; // Null-terminate the password string

    printf("\nPassword entered: %s\n", password);

    return 0;
}

使用DevCpp编译器:
在这里插入图片描述

在命令行下执行:

在这里插入图片描述


然而这种以星号代替密码的方式,安全性并不是很高。因为一个星号代替一位密码,通过星号的个数可以判断密码的位数,从而缩小破解密码的范围(指定的密码长度暴力破解)。

上面的代码将printf("*");这一行删掉,将不会显示星号。

下面再给出一个更加安全的代码片,在用户进行输入的时候,连星号都不会显示:

#include <stdio.h>
#include <windows.h>

#define MAX_PASSWORD_LENGTH 20

void hidePasswordInput()
{
    DWORD mode;
    HANDLE hstdin = GetStdHandle(STD_INPUT_HANDLE);

    // 获取输入模式
    GetConsoleMode(hstdin, &mode);
    SetConsoleMode(hstdin, mode & (~ENABLE_ECHO_INPUT)); // 禁用回显输入模式
}

void showPasswordInput()
{
    DWORD mode;
    HANDLE hstdin = GetStdHandle(STD_INPUT_HANDLE);

    // 获取输入模式
    GetConsoleMode(hstdin, &mode);
    SetConsoleMode(hstdin, mode | ENABLE_ECHO_INPUT); // 启用回显输入模式
}

int main()
{
    char password[MAX_PASSWORD_LENGTH];
    int i = 0;

    printf("Enter your password: ");

    hidePasswordInput(); // 隐藏密码输入

    while (1)
    {
        char ch = getchar();

        if (ch == '\n') // 如果输入回车键,则结束循环
            break;
        else if (ch != ' ' && i < MAX_PASSWORD_LENGTH - 1)
        {
            password[i] = ch;
            i++;
        }
    }

    password[i] = '\0'; // 在密码字符串末尾添加空字符

    showPasswordInput(); // 显示密码输入

    printf("\nPassword entered: %s\n", password);

    return 0;
}

使用DevCpp编译器:
在这里插入图片描述

这里会看到完全隐藏密码。下面是命令行下运行:
在这里插入图片描述

在Linux上实现

环境:Ubuntu,gcc 或 g++ 编译器,如果没有这两个编译器,可以使用下面的命令进行安装。
sudo apt-get install gcc
sudo apt-get install g++
gcc和g++编译:
gcc -o test test.cg++ -o test test.cpp
带有math.h的源文件: gcc test.c test -lmg++ test.c test -lm
执行:./test./的意思是当前目录,test 是编译好的可执行文件。

回显星号

#include <stdio.h>
#include <stdlib.h>
#include <termios.h>

#define MAX_PASSWORD_LENGTH 20

// 从终端获取密码(隐藏输入)
void getPassword(char* password) {
    struct termios oldAttr, newAttr;
    
    // 禁止终端回显
    tcgetattr(fileno(stdin), &oldAttr);
    newAttr = oldAttr;
    newAttr.c_lflag &= ~(ICANON | ECHO);
    tcsetattr(fileno(stdin), TCSAFLUSH, &newAttr);
    
    // 读取密码
    int i = 0;
    char c;
    while ((c = getchar()) != '\n' && i < MAX_PASSWORD_LENGTH - 1) {
        password[i++] = c;
        putchar('*');  // 回显星号
    }
    password[i] = '\0';
    
    // 恢复终端设置
    tcsetattr(fileno(stdin), TCSANOW, &oldAttr);
}

int main() {
    char password[MAX_PASSWORD_LENGTH];
    
    printf("请输入密码:");
    getPassword(password);
    
    printf("\n你输入的密码是:%s\n", password);
    
    return 0;
}

代码解读

struct termios oldAttr, newAttr;

这行语句定义了两个struct termios类型的结构体变量,分别命名为oldAttrnewAttr

struct termios是在头文件termios.h中定义的结构体。它用于保存终端设备的属性配置信息,包括输入输出模式、控制字符、特殊控制字符等。

在这行语句中,通过声明变量oldAttrnewAttrstruct termios类型,我们创建了两个变量来保存终端设备的属性。通常情况下,我们将使用oldAttr变量来保存当前终端设备的属性配置,而newAttr变量则用于修改和存储新的属性配置。

接下来,在代码的后续部分,我们可以通过对这两个变量的操作,比如修改特定属性标志位,实现对终端设备属性的更改与恢复。


在使用termios库控制终端设备属性时,通常需要保存当前终端设备的属性配置,并对其进行修改后再恢复回原来的状态。这种处理方式可以实现修改终端属性而不破坏原有状态的目的。

因此,我们需要至少两个struct termios结构体变量:

  1. 一个用于保存当前终端设备的属性配置,即原有的属性配置。这样,当我们修改终端属性后,可以将其恢复为原先的状态,确保程序执行完毕后终端属性还原为用户所期望的状态。这个结构体变量通常被命名为oldAttr,表示原有的属性配置。
  2. 另一个用于修改和存储新的属性配置。当我们想要改变终端设备的属性时,我们将使用该结构体变量保存需要修改的属性配置,然后通过相应的操作将新的属性配置应用到终端设备上。这个结构体变量通常被命名为newAttr,表示新的属性配置。

通过定义两个不同的struct termios结构体变量,我们能够分别保存原有的属性配置和新的属性配置,便于在操作终端属性时进行对比、修改和恢复。这样能够更灵活地控制终端设备的属性,同时确保安全地对属性进行修改和恢复操作。


这行代码使用了tcgetattr()函数来获取标准输入(stdin)的终端属性,并将其保存到oldAttr变量所代表的结构体中。

具体解释如下:

tcgetattr()是termios库中的一个函数,用于获取终端设备的属性配置。它接受两个参数:文件描述符和一个指向struct termios结构体的指针。

在这行代码中,fileno(stdin)返回标准输入流(stdin)的文件描述符,作为tcgetattr()函数的第一个参数。&oldAttr表示对oldAttr结构体的地址进行传递,作为tcgetattr()函数的第二个参数。

因此,该行代码的作用是获取标准输入(stdin)的终端属性,并将这些属性保存在oldAttr结构体中,以便后续可能的属性修改或恢复操作。


这行代码用于修改newAttr结构体中的终端属性配置,具体是修改了c_lflag成员的值。

解释如下:

newAttr是一个struct termios类型的结构体,其中的c_lflag成员表示终端的本地模式标志。通过使用位运算符和按位取反操作符(~),该行代码将ICANONECHO标志位从c_lflag中移除。

  • ICANON是一个终端模式标志,表示是否启用规范模式。在规范模式下,输入会以行为单位缓冲,即需要用户按下回车键才会传输到程序中处理。通过将ICANON标志位置为0,这行代码禁用了规范模式,可以实现字符无需等待回车键响应即可输入的效果。
  • ECHO是一个终端模式标志,表示是否在屏幕上显示输入的字符。通过将ECHO标志位置为0,这行代码禁止终端将用户输入的字符回显到屏幕上,使得输入的字符不可见。

因此,该行代码的作用是在newAttr结构体中关闭规范模式和字符回显,对应的终端属性被修改为禁用这两个特性。


当单独解释这行代码中的每个符号时,可以得到以下详细解释:

  • &= 是一个复合赋值运算符,用于对变量进行按位与操作后再赋值。它将左边的操作数与右边的操作数进行按位与运算,并将结果赋值给左边的操作数。
  • | 是按位或运算符,用于将两个操作数的每个对应位进行逻辑或运算,得到的结果作为新的值。如果两个操作数的任意一位为1,结果的对应位也将是1。

在代码中,newAttr.c_lflag &= ~(ICANON | ECHO); 将结构体 newAttr 中成员 c_lflag 的值与 (ICANON | ECHO) 进行按位与运算后再赋值给 c_lflag,具体步骤如下:

  1. ICANONECHO 是两个常量,代表各自指定的位标志。
  2. ICANON | ECHO 使用按位或运算符 |ICANONECHO 的位标志进行合并,并得到一个新的值,该值的位组合了这两个标志的状态。
  3. ~(ICANON | ECHO) 使用按位取反操作符 ~ 对上一步得到的值进行取反运算,即将所有位取反(1 变为 0,0 变为 1),得到一个新的值。
  4. newAttr.c_lflag &= ~(ICANON | ECHO)newAttr.c_lflag 的当前值与上一步得到的取反值进行按位与运算,然后将结果赋值给 newAttr.c_lflag。这个操作会将 newAttr.c_lflag 中对应于 (ICANON | ECHO) 标志位为 1 的位清零,而保留其余位的值不变。

综上所述,这行代码的作用是通过按位与运算和按位取反操作,将结构体 newAttr 中成员 c_lflag 的指定标志位清零,即禁用了规范模式和字符回显。


这行代码用于将修改后的终端属性应用到标准输入(stdin)。

以下是该行代码的详细解释:

  • tcsetattr(fileno(stdin), TCSAFLUSH, &newAttr); 是一个函数调用语句,调用了tcsetattr()函数。
  • tcsetattr() 是一个系统调用函数,用于设置终端的属性。它接受三个参数:文件描述符、操作选项和指向termios结构体的指针。
  • fileno(stdin) 是一个函数调用,stdin是标准输入流的文件指针,而fileno()函数用于获取对应文件指针的文件描述符。
  • stdin 是一个C语言中预定义的标准输入流。它是与程序相连的默认输入流,通常用于从用户读取输入。
  • TCSAFLUSH 是一个操作选项,用于指定在应用新的终端属性之前如何处理已经存在的输入输出数据。
    • TCSAFLUSH 选项表示丢弃尚未传输给进程的输入数据,并且清空已经缓冲但尚未传输给终端的输出数据。
    • 具体而言,使用 TCSAFLUSH 选项会执行以下操作:首先等待缓冲区中所有的数据都已传输完毕,接着将终端的属性设置为新值,最后丢弃缓冲中尚未传输的数据。
  • &newAttr 是传递给 tcsetattr() 函数的第三个参数,它是指向 newAttr 结构体的指针。这个结构体包含了要应用到终端的新属性值。

综上所述,这行代码的作用是将修改后的终端属性应用到标准输入(stdin),以及通过指定的操作选项(TCSAFLUSH)来处理已经存在的输入输出数据。


在代码tcsetattr(fileno(stdin), TCSANOW, &oldAttr);中,TCSANOW是一个操作选项,用于指定终端属性修改的立即生效方式。

具体而言,TCSANOW选项表示立即将新的终端属性值应用到终端。无需等待现有输入输出数据的处理或刷新,新的属性立即生效。

与之相比,TCSAFLUSH选项(在上一个问题中提到过)在应用新的终端属性之前会丢弃尚未传输给进程的输入数据,并清空已经缓冲但尚未传输给终端的输出数据。

因此,tcsetattr()函数根据不同的操作选项来决定何时应用新的终端属性,并处理缓冲区中的输入输出数据。

运行

请添加图片描述

完全隐藏

#include <stdio.h>
#include <stdlib.h>
#include <termios.h>

#define MAX_PASSWORD_LENGTH 20

// 从终端获取密码(隐藏输入)
void getPassword(char* password) {
    struct termios oldAttr, newAttr;
    
    // 禁止终端回显
    tcgetattr(fileno(stdin), &oldAttr);
    newAttr = oldAttr;
    newAttr.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | ICANON);
    tcsetattr(fileno(stdin), TCSAFLUSH, &newAttr);
    
    // 读取密码
    fgets(password, MAX_PASSWORD_LENGTH, stdin);
    
    // 恢复终端设置
    tcsetattr(fileno(stdin), TCSANOW, &oldAttr);
}

int main() {
    char password[MAX_PASSWORD_LENGTH];
    
    printf("请输入密码:");
    getPassword(password);
    
    printf("\n你输入的密码是:%s\n", password);
    
    return 0;
}

newAttr.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | ICANON); 这行代码的作用是修改newAttr结构体中的c_lflag字段,以关闭终端的回显和规范模式。

让我们逐个解释其中的操作:

  1. ~ 运算符:它会对括号内的值进行按位取反操作。在这里,它用于将后面括号内的各个标志取反。这样做的目的是为了关闭这些标志所代表的功能。
    1. ECHO:表示在用户从键盘输入时回显(显示)所输入的字符。
  2. ECHOE:表示擦除错误处理。当用户输入退格键或删除键时,会擦除之前输入的字符。
  3. ECHOK:表示擦除当前行的处理。如果用户输入了一个换行符(Enter键),则会擦除当前行。
  4. ECHONL:表示换行处理。如果设备支持,新的一行将以回车符和换行符结尾。
  5. ICANON:表示规范模式。在规范模式下,终端会对输入进行行缓冲处理,直到接收到一个换行符才将数据传递给程序。

因此,通过对newAttr.c_lflag字段进行按位与取反的操作,代码将关闭上述描述的回显和规范模式相关的功能,从而达到修改终端属性的目的。

运行

请添加图片描述




本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/654629.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【数学建模】2019 年全国大学生数学建模竞赛C题全国一等奖获奖论文

2021 年高教社杯全国大学生数学建模竞赛题目 机场的出粗车问题 大多数乘客下飞机后要去市区&#xff08;或周边&#xff09;的目的地&#xff0c;出租车是主要的交通工具之一。国内多数机场都是将送客&#xff08;出发&#xff09;与接客&#xff08;到达&#xff09;通道分开…

2. windows系统下在QT中配置OPenCV开发环境

1. 说明: 在Windows系统中配置相对简单,不需要对下载的源码进行编译,在官网上下载的OPenCV可以直接使用,本文系统版本为win10,opencv是最新版本4.7.0。 效果展示: 2. 配置步骤: 2.1 下载OPenCV压缩包 打开opencv的官网OPenCV下载地址,可以在其页面内下载到最新的压…

iPhone手机UDID获取方法

UDID&#xff1a;iOS设备的唯一识别码&#xff0c;每台iOS设备都有一个独一无二的编码&#xff0c;这个编码&#xff0c;就称为识别码&#xff0c;也叫做UDID&#xff08;Unique Device Identifier&#xff09; 一、通过Xcode查看 手机连接电脑打开Xcode&#xff0c;选择wind…

入职2个月,那个高薪挖来的自动化软件测试被劝退了....

其实&#xff0c;在很多小伙伴的想法中&#xff0c;是希望通过跳槽实现薪酬涨幅&#xff0c;可是跳槽不是冲动后决定&#xff0c;应该谨慎啊~ 01 我的学弟&#xff0c;最近向我吐槽&#xff0c;2020 年上半年入职一家公司&#xff0c;当时是高薪挖走的他&#xff0c;所谓钱到…

阿里云无影云电脑使用教程全流程(5分钟上手)

阿里云无影云电脑即无影云桌面&#xff0c;云桌面如何使用&#xff1f;云桌面购买后没有用户名和密码&#xff0c;先创建用户设置密码&#xff0c;才可以登录连接到云桌面。云桌面想要访问公网还需要开通互联网访问功能。阿里云百科来详细说下阿里云无影云电脑从购买、创建用户…

h264结构与码流

h264基本概念结构图 H264视频压缩后会成为一个序列帧&#xff0c;帧里包含图像&#xff0c;图像分为很多片&#xff0c;每个片可以分为宏块&#xff0c;每个宏块由许多子块组成 H264结构中&#xff0c;一个视频图像编码后的数据叫做一帧&#xff0c;一帧由一个片&#xff08;sl…

Redis系列--布隆过滤器(Bloom Filter)

一、前言 在实际开发中&#xff0c;会遇到很多要判断一个元素是否在某个集合中的业务场景&#xff0c;类似于垃圾邮件的识别&#xff0c;恶意ip地址的访问&#xff0c;缓存穿透等情况。类似于缓存穿透这种情况&#xff0c;有许多的解决方法&#xff0c;如&#xff1a;redis存储…

Python 自动化测试五种自动化测试模型实战详解

目录 前言&#xff1a; 自动化测试模型都有哪些&#xff1f; 线性模型 模块化驱动模型 数据驱动模型 关键字驱动模型 行为驱动模型 扩展知识 前言&#xff1a; Python是一种流行的编程语言&#xff0c;广泛应用于自动化测试领域。自动化测试可以帮助测试人员更快、更准确地发…

人脸识别4:Android InsightFace实现人脸识别Face Recognition(含源码)

人脸识别4&#xff1a;Android InsightFace实现人脸识别Face Recognition(含源码) 目录 人脸识别4&#xff1a;Android InsightFace实现人脸识别Face Recognition(含源码) 1. 前言 2. 项目说明 &#xff08;1&#xff09;开发版本 &#xff08;2&#xff09;依赖库说明(O…

uniapp微信开发者工具效果正常,真机上显示不出效果

1.问题描述 如上图&#xff0c;我需要给页面加入两个icons&#xff0c;页面属于分包内页面&#xff0c;icons使用的uni-icons组件&#xff0c;微信开发者工具中显示效果一切正常&#xff0c;但是在真机上预览页面显示错乱&#xff0c;没有图标&#xff0c;其他数据也显示不出来…

DJ3-7 TCP:拥塞控制

目录 一、拥塞控制概述 二、TCP 拥塞控制算法 1. 慢启动 2. 拥塞避免 3. 快速恢复 4. 状态转换图 5. 拥塞窗口的变化举例 一、拥塞控制概述 1. 如何限制发送方发送速率 TCP 拥塞控制设置 拥塞窗口 变量&#xff0c;表示为 cwnd&#xff1a; 它对发送方向网络中发送流…

A+CLUB管理人支持计划第五期 | 鸣熙资产

免责声明 本文内容仅对合格投资者开放&#xff01; 私募基金的合格投资者是指具备相应风险识别能力和风险承担能力&#xff0c;投资于单只私募基金的金额不低于100 万元且符合下列相关标准的单位和个人&#xff1a; &#xff08;一&#xff09;净资产不低于1000 万元的单位&a…

init与zygote的启动流程

文章目录 1.init进程启动过程1.1init进程的入口函数1.1.1创建和启动所需要的文件目录1.1.2对属性进行初始化与启动属性服务1.1.3子进程信号处理函数1.1.4.重启死去的进程1.1.5.解析init.rc配置文件 1.2解析init.rc配置文件1.3解析Service语句1.4init启动Zygote1.4.1start方法 1…

Android kotlin 实现仿淘宝RecyclerView和对应下的指示器功能

文章目录 一、实现效果二、引入依赖三、源码实现1、指示器样式(自定义类)2、RecyclerView适配器3、主视图实现一、实现效果 指示器样式,第二个gif是用模拟器的,gif有小问题,第三个截图没问题 二、引入依赖 在app的build.gradle在添加以下代码 1、implementation com.githu…

数字电路基础---组合逻辑

目录 数字电路基础---组合逻辑 1、简介 2、实验任务 3、程序设计 4、仿真验证 数字电路基础---组合逻辑 FPGA 或者 IC 内部的逻辑一般包括组合逻辑和时序逻辑&#xff0c;组合逻辑一般指的是一些门电路或者选择器、比较器一起组成的逻辑。 1、简介 数字电路根据逻辑功能的…

程序员必备超好用下载器IDM(Windows下载)

程序员必备现役最强下载器IDM&#xff08;Windows下载&#xff09; 1 介绍 IDM&#xff0c;全称Internet Download Maneger&#xff0c;在下载界可谓是大名鼎鼎&#xff0c;不仅仅是其强大的32线程下载&#xff0c;还因为其无与伦比的资源嗅探功能&#xff0c;Internet Downlo…

监听关闭浏览器触发事件

关闭和刷新页面都会触发&#xff0c;一般都不用来做弹窗提示&#xff0c;一般用来做数据操作 // 监听页面关闭 清除本地缓存 window.onbeforeunload function (e) { localStorage.removeItem("statement"); }; // 监听页面关闭 提醒是否关闭 现在不允许自定义内容了…

生命周期监听的使用和源码解析

定义SpringApplicationRunListener来监听springApplication的启动 1.通过实现springApplicationRunListener来实现监听。 2.在 META-INF/spring.factories 中配置 org.springframework.boot.SpringApplicationRunListener自己的Listener。 在默认的springboot配置中就有给我…

主数据概念过时了吗,在这些大数据技术背景下,数据平台等新技术的出现,我们还需要主数据吗?

当企业信息化发展到一定程度时, 数据管理必然会被提升为企业的一个重要管理领域。数据管理的好坏程度, 很大程度上影响着企业信息化进程, 决定着企业信息化最终的成效。 企业信息化建设基本上都是从部门级开始的, 从部门的实际业务需要出发独立建设信息系统, 随着这些信息系统…

2023年地图产业研究报告

第一章 行业概况 地图行业是一个快速发展且关键的信息技术领域&#xff0c;通过收集、处理和可视化地理信息&#xff0c;为用户提供导航、位置服务、地理信息系统和地图数据分析等应用。地图行业的发展受益于全球定位系统&#xff08;GPS&#xff09;技术的进步和移动设备的普…