Mbedtls和Opesnssl 解码x509Certificate
最近项目需要添加解码x509Certificate功能,可以使用openssl或者mbedtls库。对这两个库的使用总结一下。
一 Openssl解码x509 Certificate
1. 初始化
将一段buffer转化成openssl格式
const unsigned char* certificateValue = (unsigned char*)certificate->Value().data(); //这里的certificate是接收到的一段buffer
X509* m_certificate = d2i_X509(nullptr, &certificateValue, certificate->Value().size());
2. 获得版本号
int32_t certVersion = X509_get_version(m_certificate);
3. 获得序列号
const ASN1_INTEGER* ans1SerialNum = X509_get_serialNumber(m_certificate);
BIGNUM* bigSerialNUm = ASN1_INTEGER_to_BN(ans1SerialNum, nullptr);
char* serialNum = BN_bn2hex(bigSerialNUm);
serialNumber = std::string(serialNum, strlen(serialNum));
BN_free(bigSerialNUm);
OPENSSL_free(serialNum);
4. 获得公钥类型
const EVP_PKEY* pubKey = X509_get_pubkey(m_certificate);
switch (pubKey->type) {
case EVP_PKEY_RSA:
type = X509CertPubKeyType::PUB_KEY_TYPE_RSA;
break;
case EVP_PKEY_EC:
type = X509CertKeyAlgType::PUB_KEY_TYPE_ECKEY;
break;
case EVP_PKEY_DSA:
type = X509CertKeyAlgType::PUB_KEY_TYPE_ECDSA;
break;
case EVP_PKEY_DH:
type = X509CertKeyAlgType::PUB_KEY_TYPE_ECKEY_DH;
break;
default:
type = X509CertKeyAlgType::PUB_KEY_TYPE_UNKNOWN;
break;
}
5. 获得公钥使用类型
X509_check_ca(m_certificate);
if ((m_certificate->ex_kusage & KU_DATA_ENCIPHERMENT) == KU_DATA_ENCIPHERMENT) {
type = X509CertKeyUseType::KEY_USE_TYPE_EXCH;
}
else if ((m_certificate->ex_kusage & KU_DIGITAL_SIGNATURE) == KU_DIGITAL_SIGNATURE) {
type = X509CertKeyUseType::KEY_USE_TYPE_SIGN;
}
else {
type = X509CertKeyUseType::KEY_USE_TYPE_UNKNOWN;
}
6. 获得签名算法类型
const ASN1_OBJECT* signAlg = m_certificate->sig_alg.algorithm;
const int32_t oidMaxLen = 128;
char oid[oidMaxLen] = { 0 };
OBJ_obj2txt(oid, oidMaxLen, signAlg, 1);
std::string strOid(oid, strlen(oid)); const std::string CERT_SIG_ALG_RSA_RSA = "1.2.840.113549.1.1.1";
const std::string CERT_SIG_ALG_MD2RSA = "1.2.840.113549.1.1.2";
const std::string CERT_SIG_ALG_MD4RSA = "1.2.840.113549.1.1.3";
const std::string CERT_SIG_ALG_MD5RSA = "1.2.840.113549.1.1.4";
const std::string CERT_SIG_ALG_SHA1RSA = "1.2.840.113549.1.1.5";
const std::string CERT_SIG_ALG_SM3SM2 = "1.2.156.10197.1.501"; if (strOid == CERT_SIG_ALG_RSA_RSA) {
type = X509CertSigAlgType::SIG_ALG_TYPE_RSA_RSA;
}
else if (strOid == CERT_SIG_ALG_MD2RSA) {
type = X509CertSigAlgType::SIG_ALG_TYPE_MD2RSA;
}
else if (strOid == CERT_SIG_ALG_MD4RSA) {
type = X509CertSigAlgType::SIG_ALG_TYPE_MD4RSA;
}
else if (strOid == CERT_SIG_ALG_MD5RSA) {
type = X509CertSigAlgType::SIG_ALG_TYPE_MD5RSA;
}
else if (strOid == CERT_SIG_ALG_SHA1RSA) {
type = X509CertSigAlgType::SIG_ALG_TYPE_SHA1RSA;
}
else if (strOid == CERT_SIG_ALG_SM3SM2) {
type = X509CertSigAlgType::SIG_ALG_TYPE_SM3SM2;
}
else {
type = X509CertSigAlgType::SIG_ALG_TYPE_UNKNOWN;
}
7. 获得发布者名字
X509_NAME* issuerName = X509_get_issuer_name(m_certificate);
name = ConvertName(issuerName); //自定义函数
8. 获得证书持有者
X509_NAME* subjectName = X509_get_subject_name(m_certificate);
name = ConvertName(subjectName);
9. 获得证书有效时间起点
const ASN1_TIME* start = X509_get_notBefore(m_certificate);
time = ConvertTime(start);//自定义函数
10. 获得证书结束时间
const ASN1_TIME* end = X509_get_notAfter(m_certificate);
time = ConvertTime(end);
11. 获得公钥使用
const ASN1_BIT_STRING* keyUsage = (ASN1_BIT_STRING*)X509_get_ext_d2i(m_certificate, NID_key_usage, nullptr, nullptr);
uint16_t val = keyUsage->data[0];
if (keyUsage->length > 1) {
val |= keyUsage->data[1] << 8;
}
if (val & MBEDTLS_X509_KU_DIGITAL_SIGNATURE) {
usage += "Digital Signature, ";
}
if (val & MBEDTLS_X509_KU_NON_REPUDIATION) {
usage += "Non-Repudiation, ";
}
if (val & MBEDTLS_X509_KU_KEY_ENCIPHERMENT) {
usage += "Key Encipherment, ";
}
if (val & MBEDTLS_X509_KU_DATA_ENCIPHERMENT) {
usage += "Data Encipherment, ";
}
if (val & MBEDTLS_X509_KU_KEY_AGREEMENT) {
usage += "Key Agreement, ";
}
if (val & MBEDTLS_X509_KU_KEY_CERT_SIGN) {
usage += "Certificate Signature, ";
}
if (val & MBEDTLS_X509_KU_CRL_SIGN) {
usage += "CRL Signature, ";
}
const int32_t valMaxLen = 32;
char value[valMaxLen] = { 0 };
sprintf_s(value, valMaxLen, "(%x)", val);
usage += std::string(value, strlen(value));
12. 获得强化公钥使用
EXTENDED_KEY_USAGE* enUsage = (EXTENDED_KEY_USAGE*)X509_get_ext_d2i(m_certificate, NID_ext_key_usage, nullptr, nullptr);
for (int i = 0; i < sk_ASN1_OBJECT_num(enUsage); i++) {
const int32_t objMaxLen = 128;
char objId[objMaxLen] = { 0 };
char objName[objMaxLen] = { 0 };
const ASN1_OBJECT* obj = sk_ASN1_OBJECT_value(enUsage, i);
OBJ_obj2txt(objId, sizeof(objId), obj, 1);
OBJ_obj2txt(objName, sizeof(objName), obj, 0);
if (!usage.empty()) {
usage += "; ";
}
usage += objName + std::string(" (") + objId + ")";
}
sk_ASN1_OBJECT_pop_free(enUsage, ASN1_OBJECT_free);
13. 获得基础限制
BASIC_CONSTRAINTS* bcons = (BASIC_CONSTRAINTS*)X509_get_ext_d2i(m_certificate, NID_basic_constraints, nullptr, nullptr);
if (bcons->ca == 0) {
constraints += "Subject Type=End Entity; Path Length Constraint=None";
}
else {
std::string pathLenConstraint = nullptr == bcons->pathlen ? "None" : std::string((char*)bcons->pathlen->data);
constraints += "Subject Type=CA; " + std::string("Path Length Constraint=") + pathLenConstraint;
}
BASIC_CONSTRAINTS_free(bcons);
14. 获得SAN
STACK_OF(GENERAL_NAME)* extensions = (STACK_OF(GENERAL_NAME)*)X509_get_ext_d2i(m_certificate, NID_subject_alt_name, nullptr, nullptr);
for (int i = 0; i < sk_GENERAL_NAME_num(extensions); i++) {
const GENERAL_NAME* nval = sk_GENERAL_NAME_value(extensions, i);
if (nval->type == GEN_DNS) {
const unsigned char* dnsName = ASN1_STRING_get0_data(nval->d.dNSName);
dnsNames.push_back("DNS Name=" + std::string((const char*)dnsName));
}
else if (nval->type == GEN_IPADD) {
const unsigned char* ipAddr = ASN1_STRING_get0_data(nval->d.iPAddress);
ipAddrs.push_back("IP Address=" + ConvertIpAddr(ipAddr));//ConvertIpAddr是自定义函数
}
else if (nval->type == GEN_URI) {
const unsigned char* uri = ASN1_STRING_get0_data(nval->d.uniformResourceIdentifier);
uris.push_back("URL=" + std::string((const char*)uri));
}
else if (nval->type == GEN_DIRNAME) {
X509_NAME* dirName = nval->d.directoryName;
dirNames.push_back("Directory Name=" + ConvertName(dirName));
}
else if (nval->type == GEN_EMAIL) {
const unsigned char* email = ASN1_STRING_get0_data(nval->d.rfc822Name);
emails.push_back("RFC822 Name=" + std::string((const char*)email));
}
}
sk_GENERAL_NAME_pop_free(extensions, GENERAL_NAME_free)
15. 自定义函数ConvertName
std::string ConvertName(X509_NAME * name)
{
if (nullptr == name) {
return "";
}
const int32_t partNameMaxLen = 256;
char partName[partNameMaxLen] = { 0 };
std::string strName;
int returnLen = X509_NAME_get_text_by_NID(name, NID_countryName, partName, partNameMaxLen);
if (returnLen > 0) {
strName += "C=" + std::string(partName, strlen(partName)) + ", ";
}
memset(partName, 0, partNameMaxLen);
returnLen = X509_NAME_get_text_by_NID(name, NID_organizationalUnitName, partName, partNameMaxLen);
if (returnLen > 0) {
strName += "OU=" + std::string(partName, strlen(partName)) + ", ";
}
memset(partName, 0, partNameMaxLen);
returnLen = X509_NAME_get_text_by_NID(name, NID_commonName, partName, partNameMaxLen);
if (returnLen > 0) {
strName += "CN=" + std::string(partName, strlen(partName));
} return strName;
}
16. 自定义函数ConvertTime
std::string ConvertTime(const ASN1_TIME * time)
{
if (nullptr == time) {
return "";
}
std::shared_ptr<tm> tmTime(new tm());
int res = ASN1_TIME_to_tm(time, tmTime.get());
if (res == 0) {
return "";
}
const int32_t bufMaxLen = 256;
char buf[bufMaxLen] = { 0 };
int32_t basicYear = 1900;
int32_t basicMon = 1;
int32_t basicDay = 0;
int32_t basicHour = 8;
int32_t basicMin = 0;
int32_t basicSec = 0;
#ifdef _WIN32
sprintf_s(buf, "%d-%d-%d %d:%d:%d", tmTime->tm_year + basicYear, tmTime->tm_mon + basicMon, tmTime->tm_mday + basicDay,
tmTime->tm_hour + basicHour, tmTime->tm_min + basicMin, tmTime->tm_sec + basicSec);
#else
sprintf(buf, "%d-%d-%d %d:%d:%d", tmTime->tm_year + basicYear, tmTime->tm_mon + basicMon, tmTime->tm_mday + basicDay,
tmTime->tm_hour + basicHour, tmTime->tm_min + basicMin, tmTime->tm_sec + basicSec);
#endif
return std::string(buf, strlen(buf));
}
17. 自定义函数ConvertIp
std::string ConvertIpAddr(const unsigned char* ipv4octet)
{
if (nullptr == ipv4octet) {
return "";
}
std::string ipAddr;
for (auto i = 0; i < 4; i++)
{
if (!ipAddr.empty())
{
ipAddr += '.';
} char bits[4] = { 0 };
#ifdef _WIN32
sprintf_s(bits, sizeof(bits), "%d", ipv4octet[i]);
#else
snprintf(bits, sizeof(bits), "%d", ipv4octet[i]);
#endif // _WIN32
ipAddr.append(bits);
}
return ipAddr;
}
二 Mbedtls解码x509 Certificate
mbedtls的相关资料很少,自己也是研究了很长时间。并且SAN只支持Hostname
1. 初始化
将一段buffer转化成mbedtls类型
mbedtls_x509_crt_init(m_certificate);
uint32_t status = mbedtls_x509_crt_parse(m_certificate, (const unsigned char*)certificate->Value().data(), certificate->Value().size());
2. 获得版本号
int32_t certVersion = m_certificate->version;
3. 获得序列号
mbedtls_mpi mpi;
mbedtls_mpi_init(&mpi);
uint32_t status = mbedtls_mpi_read_binary(&mpi, m_certificate->serial.p, m_certificate->serial.len);
const int32_t strMaxLen = 128;
char str[strMaxLen] = { 0 };
size_t returnLen;
uint32_t radix = 16;
status = mbedtls_mpi_write_string(&mpi, radix, str, strMaxLen, &returnLen);
serialNumber = std::string(str, strlen(str));
mbedtls_mpi_free(&mpi);
4. 获得公钥类型
mbedtls_pk_type_t pubKeyType = mbedtls_pk_get_type(&m_certificate->pk);
switch (pubKeyType) {
case mbedtls_pk_type_t::MBEDTLS_PK_RSA:
type = X509CertPubKeyType::PUB_KEY_TYPE_RSA;
break;
case mbedtls_pk_type_t::MBEDTLS_PK_ECKEY:
type = X509CertPubKeyType::PUB_KEY_TYPE_ECKEY;
break;
case mbedtls_pk_type_t::MBEDTLS_PK_ECKEY_DH:
type = X509CertPubKeyType::PUB_KEY_TYPE_ECKEY_DH;
break;
case mbedtls_pk_type_t::MBEDTLS_PK_ECDSA:
type = X509CertPubKeyType::PUB_KEY_TYPE_ECDSA;
break;
case mbedtls_pk_type_t::MBEDTLS_PK_RSA_ALT:
type = X509CertPubKeyType::PUB_KEY_TYPE_RSA_ALT;
break;
case mbedtls_pk_type_t::MBEDTLS_PK_RSASSA_PSS:
type = X509CertPubKeyType::PUB_KEY_TYPE_RSASSA_PSS;
break;
default:
type = X509CertPubKeyType::PUB_KEY_TYPE_UNKNOWN;
break;
}
5. 获得公钥使用类型
if ((m_certificate->key_usage & MBEDTLS_X509_KU_DATA_ENCIPHERMENT) == MBEDTLS_X509_KU_DATA_ENCIPHERMENT) {
type = X509CertKeyUseType::KEY_USE_TYPE_EXCH;
}
else if ((m_certificate->key_usage & MBEDTLS_X509_KU_DIGITAL_SIGNATURE) == MBEDTLS_X509_KU_DIGITAL_SIGNATURE) {
type = X509CertKeyUseType::KEY_USE_TYPE_SIGN;
}
else {
type = X509CertKeyUseType::KEY_USE_TYPE_UNKNOWN;
}
6. 获得签名算法类型
mbedtls_md_type_t mdType;
mbedtls_pk_type_t pkType;
uint32_t status = mbedtls_oid_get_sig_alg(&m_certificate->sig_oid, &mdType, &pkType);
if (mdType == MBEDTLS_MD_MD2 && pkType == MBEDTLS_PK_RSA) {
type = X509CertSigAlgType::SIG_ALG_TYPE_MD2RSA;
}
else if (mdType == MBEDTLS_MD_MD4 && pkType == MBEDTLS_PK_RSA) {
type = X509CertSigAlgType::SIG_ALG_TYPE_MD4RSA;
}
else if (mdType == MBEDTLS_MD_MD5 && pkType == MBEDTLS_PK_RSA) {
type = X509CertSigAlgType::SIG_ALG_TYPE_MD5RSA;
}
else if (mdType == MBEDTLS_MD_SHA1 && pkType == MBEDTLS_PK_RSA) {
type = X509CertSigAlgType::SIG_ALG_TYPE_SHA1RSA;
}
else if (mdType == MBEDTLS_MD_SHA224 && pkType == MBEDTLS_PK_RSA) {
type = X509CertSigAlgType::SIG_ALG_TYPE_SHA224RSA;
}
else if (mdType == MBEDTLS_MD_SHA256 && pkType == MBEDTLS_PK_RSA) {
type = X509CertSigAlgType::SIG_ALG_TYPE_SHA256RSA;
}
else if (mdType == MBEDTLS_MD_SHA384 && pkType == MBEDTLS_PK_RSA) {
type = X509CertSigAlgType::SIG_ALG_TYPE_SHA384RSA;
}
else if (mdType == MBEDTLS_MD_SHA512 && pkType == MBEDTLS_PK_RSA) {
type = X509CertSigAlgType::SIG_ALG_TYPE_SHA512RSA;
}
else {
type = X509CertSigAlgType::SIG_ALG_TYPE_UNKNOWN;
}
7. 获得发布者名字
const char* shortName = nullptr;
uint32_t status = OpcUa_Good;
do{
if (MBEDTLS_ASN1_UTF8_STRING != m_certificate->issuer.val.tag) {
continue;
}
status = mbedtls_oid_get_attr_short_name(&m_certificate->issuer.oid, &shortName);
name += shortName + std::string("=") + std::string((char*)m_certificate->issuer.val.p, m_certificate->issuer.val.len);
}while (nullptr != m_certificate->issuer.next);
8. 获得证书持有者
const char* shortName = nullptr;
uint32_t status = OpcUa_Good;
do {
if (MBEDTLS_ASN1_UTF8_STRING != m_certificate->subject.val.tag)
{
continue;
}
status = mbedtls_oid_get_attr_short_name(&m_certificate->subject.oid, &shortName);
name += shortName + std::string("=") + std::string((char*)m_certificate->subject.val.p, m_certificate->subject.val.len);
} while (nullptr != m_certificate->subject.next);
9. 获得证书起始时间
const int32_t bufMaxLen = 256;
char buf[bufMaxLen] = { 0 };
uint32_t basicHour = 8;
sprintf_s(buf, "%d-%d-%d %d:%d:%d", m_certificate->valid_from.year, m_certificate->valid_from.mon, m_certificate->valid_from.day,
m_certificate->valid_from.hour + basicHour, m_certificate->valid_from.min, m_certificate->valid_from.sec);
time = std::string(buf, strlen(buf));
10. 获得证书结束时间
const int32_t bufMaxLen = 256;
char buf[bufMaxLen] = { 0 };
uint32_t basicHour = 8;
sprintf_s(buf, "%d-%d-%d %d:%d:%d", m_certificate->valid_to.year, m_certificate->valid_to.mon, m_certificate->valid_to.day,
m_certificate->valid_to.hour + basicHour, m_certificate->valid_to.min, m_certificate->valid_to.sec);
time = std::string(buf, strlen(buf));
11. 获得证书使用
uint32_t val = m_certificate->key_usage;
if (val & MBEDTLS_X509_KU_DIGITAL_SIGNATURE) {
usage += "Digital Signature, ";
}
if (val & MBEDTLS_X509_KU_NON_REPUDIATION) {
usage += "Non-Repudiation, ";
}
if (val & MBEDTLS_X509_KU_KEY_ENCIPHERMENT) {
usage += "Key Encipherment, ";
}
if (val & MBEDTLS_X509_KU_DATA_ENCIPHERMENT) {
usage += "Data Encipherment, ";
}
if (val & MBEDTLS_X509_KU_KEY_AGREEMENT) {
usage += "Key Agreement, ";
}
if (val & MBEDTLS_X509_KU_KEY_CERT_SIGN) {
usage += "Certificate Signature, ";
}
if (val & MBEDTLS_X509_KU_CRL_SIGN) {
usage += "CRL Signature, ";
}
const int32_t valMaxLen = 32;
char value[valMaxLen] = { 0 };
sprintf_s(value, valMaxLen, "(%x)", val);
usage += std::string(value, strlen(value));
12. 获得强化公钥使用
mbedtls_x509_sequence* enKeyUsage = &m_certificate->ext_key_usage;
while( nullptr != enKeyUsage) {
const char* des = nullptr;
uint32_t status = mbedtls_oid_get_extended_key_usage(&enKeyUsage->buf, &des);
const int valMaxLen = 128;
char val[valMaxLen] = { 0 };
status = mbedtls_oid_get_numeric_string(val, valMaxLen, &enKeyUsage->buf);
if (!usage.empty()) {
usage += ";";
}
usage += des + std::string(" (") + std::string(val, strlen(val)) + ")";
enKeyUsage = enKeyUsage->next;
}
13. 获得基础限制
if (m_certificate->ca_istrue == 0) {
constraints = "Subject Type=End Entity; Path Length Constraint=None";
}
else {
std::string pathLenConstraint = 0 == m_certificate->max_pathlen ? "None" : std::to_string(m_certificate->max_pathlen);
constraints += "Subject Type=CA; " + std::string("Path Length Constraint=") + pathLenConstraint;
}
14. 获得SAN(仅支持Hostname)
mbedtls_asn1_sequence* san = &m_certificate->subject_alt_names;
while (nullptr != san) {
dnsNames.push_back(std::string((char*)san->buf.p, san->buf.len));//dsnNames类型是std::vector<std::string>
san = san->next;
}
纯原创,参考请标明出处,谢谢!!
Mbedtls和Opesnssl 解码x509Certificate的更多相关文章
- 基于MbedTLS的AES加密实现,含STM32H7和STM32F4的实现例程
说明: 1.mbedTLS的前身是PolarSSL,开源免费. 主要提供了的SSL/TLS支持(在传输层对网络进行加密),各种加密算法,各种哈希算法,随机数生成以及X.509(密码学里公钥证书的格式标 ...
- 痞子衡嵌入式:对比MbedTLS算法库纯软件实现与i.MXRT上DCP,CAAM硬件加速器实现性能差异
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是MbedTLS算法库纯软件实现与i.MXRT上DCP,CAAM硬件加速器实现性能差异. 近期有 i.MXRT 客户在集成 OTA SBL ...
- linux字符串url编码与解码
编码的两种方式 echo '手机' | tr -d '\n' | xxd -plain | sed 's/\(..\)/%\1/g' echo '手机' |tr -d '\n' |od -An -tx ...
- URI编码解码和base64
概述 对于uri的编解码,在js中有3对函数,分别是escape/unescape,encodeURI/decodeURI,encodeURIComponent/decodeURIComponent. ...
- FFmpeg学习2:解码数据结构及函数总结
在上一篇文章中,对FFmpeg的视频解码过程做了一个总结.由于才接触FFmpeg,还是挺陌生的,这里就解码过程再做一个总结. 本文的总结分为以下两个部分: 数据读取,主要关注在解码过程中所用到的FFm ...
- Unicode转义(\uXXXX)的编码和解码
在涉及Web前端开发时, 有时会遇到\uXXXX格式表示的字符, 其中XXXX是16进制数字的字符串表示形式, 在js中这个叫Unicode转义字符, 和\n \r同属于转义字符. 在其他语言中也有类 ...
- C# base 64图片编码解码
使用WinForm实现了图片base64编码解码的 效果图: 示例base 64编码字符串: /9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKD ...
- java编码原理,java编码和解码问题
java的编码方式原理 java的JVM的缺省编码方式由系统的“本地语言环境”设置确定,和操作系统的类型无关 . 在JAVA源文件-->JAVAC-->Class-->Java--& ...
- [LeetCode] Decode String 解码字符串
Given an encoded string, return it's decoded string. The encoding rule is: k[encoded_string], where ...
随机推荐
- 06.深入学习redis replication的完整流程和原理
一.replication的完整流程 slave配置master ip和port # slaveof <masterip> <masterport> slaveof 127.0 ...
- 力扣Leetcode 1248. 统计「优美子数组」
统计「优美子数组」 给你一个整数数组 nums 和一个整数 k. 如果某个 连续 子数组中恰好有 k 个奇数数字,我们就认为这个子数组是「优美子数组」. 请返回这个数组中「优美子数组」的数目. 示例 ...
- boot磁盘空间大于80警报
WARNING=80SPACE_USED=`df |grep '^/dev/sda' |tr -s ' ' %|cut -d% -f5|sort -n|tail -n1`[ "$SPACE_ ...
- Jira + confluence
Jira入门教程 敏捷开发管理(一) https://www.jianshu.com/p/145b5c33f7d0 https://www.jianshu.com/p/975385878cde JIR ...
- idea vue文件设置tab为四个空格
1.找到vue项目中有个叫.editorconfig的文件,打开可以发现有以下配置项: 2.ctrl+alt+i看看效果(单文件) 3.IDEA中对整个项目进行代码格式化 在项目的左侧树结构中,右 ...
- Linux:用户账号、密码、群组、群组密码文件查看
使用者账号密码存放文件:/etc/passwd, /etc/shadow 虽然我们登入 Linux 主机的时候,输入的是我们的账号,但是,其实 Linux 主机并不会直接认识你的『账 号名称』的,他仅 ...
- steam 数据转换
目录 数组和集合互转 数组转集合 方法一 遍历 方法二 asList 方法三 steam 集合转数组 方法一 循环 方法二 toArray 方法三 steam 小结 string转为Character ...
- MySQL数据库中几种数据类型的长度
在MySQL里新建表自然会涉及设置字段长度,但有时会发现长度限制在一些字段类型中不起作用?字段长度是按字节算还是字符算? 如图中:int看起来只要还在本身类型取值范围内就行,字段长度没有起到作用:而c ...
- vmware-workstation迁移虚拟机 15pro到12版本
最近将测试的几台虚拟机进行了迁移,有几个点要注意,分享一下 1.环境介绍: 源服务器-ip-172.16.96.x 目标服务器-ip-172.16.96.x VMware版本-VMwareworkst ...
- [BUUOJ记录] [ACTF2020 新生赛]Upload
简单的上传题,考察绕过前端Js验证,phtml拓展名的应用 打开题目点亮小灯泡后可以看到一个上传点 传一个php测试一下: 发现有文件拓展名检查,F12发现是Js前端验证: 审查元素直接删掉,继续上传 ...