最近项目需要添加解码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的更多相关文章

  1. 基于MbedTLS的AES加密实现,含STM32H7和STM32F4的实现例程

    说明: 1.mbedTLS的前身是PolarSSL,开源免费. 主要提供了的SSL/TLS支持(在传输层对网络进行加密),各种加密算法,各种哈希算法,随机数生成以及X.509(密码学里公钥证书的格式标 ...

  2. 痞子衡嵌入式:对比MbedTLS算法库纯软件实现与i.MXRT上DCP,CAAM硬件加速器实现性能差异

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是MbedTLS算法库纯软件实现与i.MXRT上DCP,CAAM硬件加速器实现性能差异. 近期有 i.MXRT 客户在集成 OTA SBL ...

  3. linux字符串url编码与解码

    编码的两种方式 echo '手机' | tr -d '\n' | xxd -plain | sed 's/\(..\)/%\1/g' echo '手机' |tr -d '\n' |od -An -tx ...

  4. URI编码解码和base64

    概述 对于uri的编解码,在js中有3对函数,分别是escape/unescape,encodeURI/decodeURI,encodeURIComponent/decodeURIComponent. ...

  5. FFmpeg学习2:解码数据结构及函数总结

    在上一篇文章中,对FFmpeg的视频解码过程做了一个总结.由于才接触FFmpeg,还是挺陌生的,这里就解码过程再做一个总结. 本文的总结分为以下两个部分: 数据读取,主要关注在解码过程中所用到的FFm ...

  6. Unicode转义(\uXXXX)的编码和解码

    在涉及Web前端开发时, 有时会遇到\uXXXX格式表示的字符, 其中XXXX是16进制数字的字符串表示形式, 在js中这个叫Unicode转义字符, 和\n \r同属于转义字符. 在其他语言中也有类 ...

  7. C# base 64图片编码解码

    使用WinForm实现了图片base64编码解码的 效果图: 示例base 64编码字符串: /9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKD ...

  8. java编码原理,java编码和解码问题

    java的编码方式原理 java的JVM的缺省编码方式由系统的“本地语言环境”设置确定,和操作系统的类型无关 . 在JAVA源文件-->JAVAC-->Class-->Java--& ...

  9. [LeetCode] Decode String 解码字符串

    Given an encoded string, return it's decoded string. The encoding rule is: k[encoded_string], where ...

随机推荐

  1. 06.深入学习redis replication的完整流程和原理

    一.replication的完整流程 slave配置master ip和port # slaveof <masterip> <masterport> slaveof 127.0 ...

  2. 力扣Leetcode 1248. 统计「优美子数组」

    统计「优美子数组」 给你一个整数数组 nums 和一个整数 k. 如果某个 连续 子数组中恰好有 k 个奇数数字,我们就认为这个子数组是「优美子数组」. 请返回这个数组中「优美子数组」的数目. 示例 ...

  3. boot磁盘空间大于80警报

    WARNING=80SPACE_USED=`df |grep '^/dev/sda' |tr -s ' ' %|cut -d% -f5|sort -n|tail -n1`[ "$SPACE_ ...

  4. Jira + confluence

    Jira入门教程 敏捷开发管理(一) https://www.jianshu.com/p/145b5c33f7d0 https://www.jianshu.com/p/975385878cde JIR ...

  5. idea vue文件设置tab为四个空格

    1.找到vue项目中有个叫.editorconfig的文件,打开可以发现有以下配置项:  2.ctrl+alt+i看看效果(单文件)  3.IDEA中对整个项目进行代码格式化 在项目的左侧树结构中,右 ...

  6. Linux:用户账号、密码、群组、群组密码文件查看

    使用者账号密码存放文件:/etc/passwd, /etc/shadow 虽然我们登入 Linux 主机的时候,输入的是我们的账号,但是,其实 Linux 主机并不会直接认识你的『账 号名称』的,他仅 ...

  7. steam 数据转换

    目录 数组和集合互转 数组转集合 方法一 遍历 方法二 asList 方法三 steam 集合转数组 方法一 循环 方法二 toArray 方法三 steam 小结 string转为Character ...

  8. MySQL数据库中几种数据类型的长度

    在MySQL里新建表自然会涉及设置字段长度,但有时会发现长度限制在一些字段类型中不起作用?字段长度是按字节算还是字符算? 如图中:int看起来只要还在本身类型取值范围内就行,字段长度没有起到作用:而c ...

  9. vmware-workstation迁移虚拟机 15pro到12版本

    最近将测试的几台虚拟机进行了迁移,有几个点要注意,分享一下 1.环境介绍: 源服务器-ip-172.16.96.x 目标服务器-ip-172.16.96.x VMware版本-VMwareworkst ...

  10. [BUUOJ记录] [ACTF2020 新生赛]Upload

    简单的上传题,考察绕过前端Js验证,phtml拓展名的应用 打开题目点亮小灯泡后可以看到一个上传点 传一个php测试一下: 发现有文件拓展名检查,F12发现是Js前端验证: 审查元素直接删掉,继续上传 ...