鸿蒙仓颉语言【cryptocj 库】RC2、 RC4 、AES对称加密算法

news2024/11/15 19:25:13

2 提供RC2、 RC4 、AES对称加密算法

前置条件:NA

场景:

  1. 支持对称加密算法。

约束:RC2密钥长度一般16字节,加密块长度8字节;AES加密块长度16字节

性能: 支持版本几何性能持平

可靠性: NA

2.1 RC2

RC2 是一种对称加密算法,所见到的安全解决方案中,使用 RC2 的算法不多,从资料上看,RC2 算法可以替代 DES 算法,而且计算速度快,能在 16 位计算机上实现,密钥长度从 1 到 128 字节都可以。一般采用 16 字节,计算的数据块为 8 字节。

支持 ecb、cbc、cfb64、ofb64 加解密

2.1.1 主要接口

注意:

  • RC2 一般采用 16 字节,计算的数据块为 8 字节,不足位补 \0,输出缓存区为一个块长 8 字节
  • 偏移量每次加解密操作需要重新赋值
  • 密钥长度从 1 到 128 字节都可以,一般采用 16 字节。
  • 加解密必须设置密钥
// 加密标识 1
public let RC2_ENCRYPT: Int32 = 1
// 解密标识 0
public let RC2_DECRYPT: Int32 = 0
// 加密块长
public let RC2_BLOCK: Int32 = 8
// 密钥长度
public let RC2_KEY_LENGTH: Int32 = 16
class RC2KEY

RC2KEY 类

public class RC2KEY {
    /*
     * 初始化 RC2KEY
     */
    public init()
}
2.1.2 全局函数
/*
 * 设置密钥
 * 
 * 参数 key - RC2 的密钥类
 * 参数 data - 密钥数据,不能为空
 * 参数 bits - 密钥数据的位数
 * 返回值 Unit
 */
public func rc2SetKey(key: RC2KEY, data: Array<UInt8>, bits: Int32): Unit 

/*
 * RC2 ecb 加解密计算
 * 
 * 参数 inside - 输入数据,一个块的长度 8
 * 参数 out - 输出缓存区,一个块的长度 8
 * 参数 key - RC2 的密钥类
 * 参数 enc - 加密/解密模式, 加密:RC2_ENCRYPT, 解密:RC2_DECRYPT
 * 返回值 Unit
 */
public func rc2EcbEncrypt(inside: Array<UInt8>, out: Array<UInt8>, key: RC2KEY, enc: Int32): Unit

/*
 * RC2 cbc加密/解密计算;
 * 
 * 参数 inside - 输入数据,一个块的长度 8
 * 参数 out - 输出缓存区,一个块的长度 8
 * 参数 ks - RC2 的密钥类
 * 参数 iv - 初始化向量
 * 参数 enc - 加密/解密模式, 加密:RC2_ENCRYPT, 解密:RC2_DECRYPT
 * 返回值 Unit
 */
public func rc2CbcEncrypt(inside: Array<UInt8>, out: Array<UInt8>, ks: RC2KEY, iv: Array<UInt8>, enc: Int32): Unit

/*
 * RC2的cfb64 加密/解密计算
 * 
 * 参数 inside - 输入数据,一个块的长度 8
 * 参数 out - 输出缓存区,一个块的长度 8
 * 参数 schedule - RC2 的密钥类
 * 参数 ivec - 初始化向量
 * 参数 num - ivec 索引
 * 参数 enc - 加密/解密模式, 加密:RC2_ENCRYPT, 解密:RC2_DECRYPT
 * 返回值 Unit
 */
public func rc2Cfb64Encrypt(inside: Array<UInt8>, out: Array<UInt8>, schedule: RC2KEY, ivec: Array<UInt8>, num: Int32, enc: Int32): Unit

/*
 * RC2的ofb64 加密
 * 
 * 参数 inside - 输入数据,一个块的长度 8
 * 参数 out - 输出缓存区,一个块的长度 8
 * 参数 schedule - RC2 的密钥类
 * 参数 ivec - 初始化向量
 * 参数 num - ivec 索引( 0<= num < RC2_BLOCK)
 * 返回值 Unit
 */
public func rc2Ofb64Encrypt(inside: Array<UInt8>, out: Array<UInt8>, schedule: RC2KEY, ivec: Array<UInt8>, num: Int32): Unit
2.1.3 示例
from crypto4cj import rc2cj.*
from crypto4cj import utils.*
from encoding import base64.*
from encoding import hex.*
from std import collection.*
from std import math.*

main() {    
    var rc2key = RC2KEY()
    var keys: String = "1234567896465451"
    var datas: String = "helloword"
    var res: Array<UInt8> = Array<UInt8>(8, item: 0)
    rc2SetKey(rc2key, keys.toUtf8Array(), 0)

    // 编码
    var inside: Array<UInt8> = datas.toUtf8Array()
    var insides2: ArrayList<Array<UInt8>> = arrayTo2Array(inside, 8)
    var a: ArrayList<UInt8> = ArrayList<UInt8>()
    for(i in 0..insides2.size) { 
        rc2EcbEncrypt(insides2[i], res, rc2key, RC2_ENCRYPT)
        var b = res
        a.appendAll(b)
    }
    var resultE = toHexString(a.toArray())
    if(resultE != "97d61c569253660da654fb13588f9c84") {
        return -1
    }

    // 解码
    var deRes: Array<UInt8> = Array<UInt8>(8, item: 0)
    var deData = fromHexString(resultE).getOrThrow()
    var insides3: ArrayList<Array<UInt8>> = arrayTo2Array(deData, 8)
    var c: ArrayList<UInt8> = ArrayList<UInt8>() 
    for(i in 0..insides3.size) { 
        rc2EcbEncrypt(insides3[i], deRes, rc2key, RC2_DECRYPT)
        var b = deRes
        c.appendAll(b)
    }

    var decryptRes = String.fromUtf8(c.toArray())
    if(!decryptRes.contains(datas)) {
        return -1
    }
    return 0
}

运行结果如下:

0

2.2 RC4

RC4(Ron Rivest Cipher 4)是一种流加密算法,密钥长度可变。它加解密使用相同的密钥,属于对称加密算法,是使用最广泛的序列密码。RC4 是一种基于非线性数据表变换的序列密码。它以一个足够大的数据表(S盒)为基础,对表进行非线性变换,产生非线性的密钥流序列。它是一个可变密钥长度、面向字节操作的序列密码,该算法以随机置换作为基础。

支持 rc4 加解密

2.2.1 主要接口
class RC4KEY

RC4KEY 类

public class RC4KEY {
    /*
     * 初始化 RC4KEY
     */
    public init()
2.2.2 全局函数
/*
 * 设置密钥
 * 
 * 参数 key - RC4 的密钥类
 * 参数 data - 密钥数据
 * 返回值 Unit
 */
public func rc4SetKey(key: RC4KEY, data: Array<UInt8>): Unit 

/*
 * RC4 加解密计算
 * 
 * 参数 key - key 值
 * 参数 indata - 加密的数据
 * 参数 outdata - 加解密后的数据
 * 返回值 Unit
 */
public func rc4(key: RC4KEY, indata: Array<UInt8>, outdata: Array<UInt8>): Unit
2.1.3 示例
from crypto4cj import rc4cj.*
from encoding import base64.*
from std import collection.*
from std import math.*

main() {    
    var keys: Array<UInt8> = "1234567891111111".toUtf8Array()
    var indata: Array<UInt8> = "helloword".toUtf8Array()
    var encodeRes = rc4Encode(indata, keys)
    var decodeRes = rc4Decode(encodeRes, keys)
    if(toBase64String(encodeRes) != "Dqd7cGrLT0a7" || String.fromUtf8(decodeRes) != "helloword") {
        return -1
    }
    return 0
}

func rc4Encode(indata: Array<UInt8>, keys: Array<UInt8>): Array<UInt8> {
    var indataLen: Int32 = Int32(indata.size)
    var keysLen: Int32 = Int32(keys.size)
    var outdata: Array<UInt8> = Array<UInt8>(Int64(indataLen) , item: 0)

    if(indataLen == 0 || keysLen == 0) {
        return outdata
    }

    var key = RC4KEY()
    rc4SetKey(key, keys)
    rc4(key, indata, outdata)
    return outdata
}

func rc4Decode(indata: Array<UInt8>, keys: Array<UInt8>): Array<UInt8> {
    var indataLen: Int32 = Int32(indata.size)
    var keysLen: Int32 = Int32(keys.size)
    var outdata: Array<UInt8> = Array<UInt8>(Int64(indataLen) , item: 0)

    if(indataLen == 0 || keysLen == 0) {
        return outdata
    }

    var key = RC4KEY()
    rc4SetKey(key, keys)
    rc4(key, indata, outdata)
    return outdata
}

运行结果如下:

0

2.3 AES

密码学中的高级加密标准(Advanced Encryption Standard,AES),又称 Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院(NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。2006年,高级加密标准已然成为对称密钥加密中最流行的算法之一。

支持 aes、ecb、cbc、cfb128、cfb1、cfb8、ofb128、Ige、bilge、wrap、unwrap 加解密

注意:

  • AES 计算的数据块一般为 16 字节(或16字节的倍数),不足位补\0
  • 调用加密函数之前,必须先设置加密key:aesSetEncryptKey
  • 调用解密函数之前,必须先设置解密key:aesSetDecryptKey
  • 对于 aesCbcEncrypt 加密解密,每次调用前必须先初始化 ivec 向量, ivec 一般为 16 字节
  • 密码长度支持 128/192/256 bits
2.3.1 主要接口
// 加密标识 1 
public let AES_ENCRYPT: Int32 = 1
// 解密标识 0
public let AES_DECRYPT: Int32 = 0
// 加密块长
public let AES_BLOCK_SIZE: Int32 = 16
class AESKEY
/*
 * 初始化 AESKEY 
 */
public init()
2.3.2 全局函数

注意:

  • userKey 长度 16、24、32
  • bits 长度 对应为 128、192、256
  • 加解密密钥需相同
func aesSetEncryptKey
/*
 * 设置加密密钥
 * 
 * 参数 userKey - 密钥,必须为 16、24、32
 * 参数 bits - 密钥位数,与 userKey ,对应为 128、192、256
 * 参数 key - AESKEY
 * 返回值 Unit
 */
public func aesSetEncryptKey(userKey: Array<UInt8>, bits: Int32, key: AESKEY): Unit
func aesSetDecryptKey
/*
 * 设置解密密钥(加解密的参数需一致)
 * 
 * 参数 userKey - 密钥,必须为 16、24、32
 * 参数 bits - 密钥位数,与 userKey ,对应为 128、192、256
 * 参数 key - AESKEY
 * 返回值 Unit
 */
public func aesSetDecryptKey(userKey: Array<UInt8>, bits: Int32, key: AESKEY): Unit
func aesEncrypt

注意:

  • AES 计算的数据块一般为 16 字节(或16字节的倍数),不足位补\0, 输出缓存区为一个数据块长 16 字节
/*
 * 加密数据
 * 
 * 参数 inside - 加密数据,一个数据块长 16 字节
 * 参数 outside - 输出缓存区,一个数据块长 16 字节
 * 参数 key - AESKEY
 * 返回值 Unit 
 */
public func aesEncrypt(inside: Array<UInt8>, outside: Array<UInt8>, key: AESKEY): Unit
func aesDecrypt

注意:

  • AES 计算的数据块一般为 16 字节(或16字节的倍数),不足位补\0,输出缓存区为一个数据块长 16 字节
/*
 * 解密数据
 * 
 * 参数 inside - 解密数据,一个数据块长 16 字节
 * 参数 outside - 输出缓存区,一个数据块长 16 字节
 * 参数 key - AESKEY
 * 返回值 Unit 
 */
public func aesDecrypt(inside: Array<UInt8>, outside: Array<UInt8>, key: AESKEY): Unit
func aesEcbEncrypt

注意:

  • AES 计算的数据块一般为 16 字节(或16字节的倍数),不足位补\0,输出缓存区为一个数据块长 16 字节
/*
 * 加解密数据
 * 
 * 参数 inside - 输入数据,一个数据块长 16 字节
 * 参数 outside - 输出缓存区,一个数据块长 16 字节
 * 参数 key - AESKEY
 * 参数 enc - 加解密参数,加密: AES_ENCRYPT = 1,解密:AES_DECRYPT = 0
 * 返回值 Unit 
 */
public func aesEcbEncrypt(inside: Array<UInt8>, outside: Array<UInt8>, key: AESKEY, enc: Int32): Unit
func aesCbcEncrypt

注意:

  • AES 计算的数据块一般为 16 字节(或16字节的倍数),不足位补\0,输出缓存区为一个数据块长 16 字节
  • 对于加密解密,每次调用前必须先初始化 ivec 向量, ivec 必须是 16 字节
/*
 * 加解密数据
 * 
 * 参数 inside - 输入数据,一个数据块长 16 字节
 * 参数 outside - 输出缓存区,一个数据块长 16 字节
 * 参数 key - AESKEY
 * 参数 ivec - 初始向量
 * 参数 enc - 加解密参数,加密: AES_ENCRYPT = 1,解密:AES_DECRYPT = 0
 * 返回值 Unit 
 */
public func aesCbcEncrypt(inside: Array<UInt8>, outside: Array<UInt8>, key: AESKEY, ivec: Array<UInt8>, enc: Int32): Unit
func aesCfb128Encrypt

注意:

  • CFB128 模式加密和解密均使用 aesSetEncryptKey,这一点比较反常,务必记住。
  • CFB128 模式可一次性加解密。
  • 对于加密解密,每次调用前必须先初始化 ivec 向量, ivec 必须是 16 字节
  • CFB128 单词中的 128 属于 cfb 模式中加解密时分组继续分段的段的大小,与密钥 128 无关
/*
 * 加解密数据
 * 
 * 参数 inside - 输入数据,长度任意
 * 参数 outside - 输出数据,长度与输入数据相等
 * 参数 key - AESKEY
 * 参数 ivec - 可读写的一块内存。长度必须是16字节。
 * 参数 enc - 加解密参数,加密: AES_ENCRYPT = 1,解密:AES_DECRYPT = 0
 * 返回值 Unit 
 */
public func aesCfb128Encrypt(inside: Array<UInt8>, outside: Array<UInt8>, key: AESKEY, ivec: Array<UInt8>, enc: Int32): Unit
func aesCfb1Encrypt

注意:

  • CFB1 模式加密和解密均使用 aesSetEncryptKey,这一点比较反常,务必记住。
  • CFB1 模式可一次性加解密。
  • 对于加密解密,每次调用前必须先初始化 ivec 向量, ivec 必须是 16 字节
  • CFB1 单词中的 1 属于 cfb 模式中加解密时分组继续分段的段的大小,与密钥 128 无关
/*
 * 加解密数据
 * 
 * 参数 inside - 输入数据,长度任意
 * 参数 outside - 输出数据,长度与输入数据相等
 * 参数 key - AESKEY
 * 参数 ivec - 可读写的一块内存。长度必须是16字节。
 * 参数 enc - 加解密参数,加密: AES_ENCRYPT = 1,解密:AES_DECRYPT = 0
 * 返回值 Unit 
 */
public func aesCfb1Encrypt(inside: Array<UInt8>, outside: Array<UInt8>, key: AESKEY, ivec: Array<UInt8>, enc: Int32): Unit
func aesCfb8Encrypt

注意:

  • CFB8 模式加密和解密均使用 aesSetEncryptKey,这一点比较反常,务必记住。
  • CFB8 模式可一次性加解密。
  • 对于加密解密,每次调用前必须先初始化 ivec 向量, ivec 必须是 16 字节
  • CFB8 单词中的 8 属于 cfb 模式中加解密时分组继续分段的段的大小,与密钥 128 无关
/*
 * 加解密数据
 * 
 * 参数 inside - 输入数据,长度任意
 * 参数 outside - 输出数据,长度与输入数据相等
 * 参数 key - AESKEY
 * 参数 ivec - 可读写的一块内存。长度必须是16字节。
 * 参数 enc - 加解密参数,加密: AES_ENCRYPT = 1,解密:AES_DECRYPT = 0
 * 返回值 Unit 
 */
public func aesCfb8Encrypt(inside: Array<UInt8>, outside: Array<UInt8>, key: AESKEY, ivec: Array<UInt8>, enc: Int32): Unit
func aesOfb128Encrypt

注意:

  • OFB128 模式加密和解密均使用 aesSetEncryptKey,这一点比较反常,务必记住。
  • OFB128 模式可一次性加解密。
  • 对于加密解密,每次调用前必须先初始化 ivec 向量, ivec 必须是 16 字节。
  • aesOfb128Encrypt函数既是加密,又是解密。当 inside 为明文时,执行的是加密操作;当 inside 为密文时,执行的是解密操作。
  • OFB128 单词中的 128 属于 Ofb 模式中加解密时分组继续分段的段的大小,与密钥 128 无关
/*
 * 加解密数据
 * 
 * 参数 inside - 输入数据,长度任意
 * 参数 outside - 输出数据,长度与输入数据相等
 * 参数 key - AESKEY
 * 参数 ivec - 可读写的一块内存。长度必须是16字节。
 * 返回值 Unit 
 */
public func aesOfb128Encrypt(inside: Array<UInt8>, outside: Array<UInt8>, key: AESKEY, ivec: Array<UInt8>): Unit
func aesIgeEncrypt

注意:

  • 可一次性加解密。
  • 对于加密解密,每次调用前必须先初始化 ivec 向量, ivec 必须是 32(加密数据块的 2 倍) 字节。
  • 输入数据长度必须是 16 的整数倍
/*
 * 加解密数据
 * 
 * 参数 inside - 输入数据,长度必须是 16 的整数倍
 * 参数 outside - 输出数据,长度与输入数据相等
 * 参数 key - AESKEY
 * 参数 ivec - 可读写的一块内存。长度必须是 32 字节(加密数据块的 2 倍)。
 * 参数 enc - 加解密参数,加密: AES_ENCRYPT = 1,解密:AES_DECRYPT = 0
 * 返回值 Unit 
 */
public func aesIgeEncrypt(inside: Array<UInt8>, outside: Array<UInt8>, key: AESKEY, ivec: Array<UInt8>, enc: Int32): Unit
func aesBiIgeEncrypt

注意:

  • 可一次性加解密。
  • 对于加密解密,每次调用前必须先初始化 ivec 向量, ivec 必须是 64(加密数据块的 4 倍) 字节。
  • 输入数据长度必须是 16 的整数倍
/*
 * 加解密数据
 * 
 * 参数 inside - 输入数据,长度必须是 16 的整数倍
 * 参数 outside - 输出数据,长度与输入数据相等
 * 参数 key - AESKEY
 * 参数 ivec - 可读写的一块内存。长度必须是 64 字节(加密数据块的 4 倍)。
 * 参数 enc - 加解密参数,加密: AES_ENCRYPT = 1,解密:AES_DECRYPT = 0
 * 返回值 Unit 
 */
public func aesBiIgeEncrypt(inside: Array<UInt8>, outside: Array<UInt8>, key: AESKEY, ivec: Array<UInt8>, enc: Int32): Unit
func aesWrapEncrypt

注意:

  • 需设置加密密钥
  • ivec 偏移量必须为 8 字节
  • 输入数据长度必须是 8 的整数倍,且 大于等于 16 位
  • 最小输出缓存区长度 = 输入数据长度 + 8
/*
 * 加解密数据
 * 
 * 参数 key - AESKEY
 * 参数 ivec - 长度必须是 8 字节
 * 参数 outside - 输出数据,等于 输入数据长度 + 8
 * 参数 inside - 输入数据,长度必须是 8 的整数倍,且 大于等于 16 位
 * 返回值 Unit 
 */
public func aesWrapEncrypt(key: AESKEY, ivec: Array<UInt8>, outside: Array<UInt8>, inside: Array<UInt8>): Unit
func aesUnWrapEncrypt

注意:

  • 需设置解密密钥
  • ivec 偏移量必须为 8 字节
  • 输入数据长度必须是 8 的整数倍,且 大于等于 24 位
  • 最小输出缓存区长度 = 输入数据长度 - 8
/*
 * 加解密数据
 * 
 * 参数 key - AESKEY
 * 参数 ivec - 长度必须是 8 字节
 * 参数 outside - 输出数据,等于 输入数据长度 + 8
 * 参数 inside - 输入数据,长度必须是 8 的整数倍,且 大于等于 24 位
 * 返回值 Unit 
 */
public func aesUnWrapEncrypt(key: AESKEY, ivec: Array<UInt8>, outside: Array<UInt8>, inside: Array<UInt8>): Unit
2.3.3 示例
from crypto4cj import aescj.*
from crypto4cj import utils.*
from encoding import hex.*
from std import collection.*
from std import unicode.*

main() {    
    var keys: Array<UInt8> = "1234567812345678".toUtf8Array()
    var inside: Array<UInt8> = "skfhafahglkahglahglkahgalg".toUtf8Array()
    var encodeRes = aesEncode(inside, keys)
    if(toHexString(encodeRes) != "7da4e06948c190ecf633625517c1e7cbd40afb1fbe2dd55438c8f806c1c549d5") {
        return -1
    }

    var decodeRes = aesDecode(encodeRes, keys)
    if(!String.fromUtf8(decodeRes).contains("skfhafahglkahglahglkahgalg")) {
        return -1
    }
    return 0
}

func aesEncode(inside: Array<UInt8>, keys: Array<UInt8>): Array<UInt8> {
    var key = AESKEY()
    var outside: Array<UInt8> = Array<UInt8>(Int64(AES_BLOCK_SIZE), item: 0)

    var keyRet = aesSetEncryptKey(keys, 128, key)

    var data: ArrayList<Array<UInt8>> = arrayTo2Array(inside, Int64(AES_BLOCK_SIZE))
    var res: ArrayList<UInt8> = ArrayList<UInt8>()
    for( i in 0..data.size ) {
        aesEncrypt(data[i], outside, key)
        res.appendAll(outside)
    }   
    return res.toArray()
}

func aesDecode(inside: Array<UInt8>, keys: Array<UInt8>): Array<UInt8> {
    var key = AESKEY()
    var outside: Array<UInt8> = Array<UInt8>(Int64(AES_BLOCK_SIZE), item: 0)

    var keyRet = aesSetDecryptKey(keys, 128, key)

    var data: ArrayList<Array<UInt8>> = arrayTo2Array(inside, Int64(AES_BLOCK_SIZE))
    var res: ArrayList<UInt8> = ArrayList<UInt8>()
    for( i in 0..data.size ) {
        aesDecrypt(data[i], outside, key)
        res.appendAll(outside)
    }   
    return res.toArray()
}

运行结果如下:

0

最后呢

很多开发朋友不知道需要学习那些鸿蒙技术?鸿蒙开发岗位需要掌握那些核心技术点?为此鸿蒙的开发学习必须要系统性的进行。

而网上有关鸿蒙的开发资料非常的少,假如你想学好鸿蒙的应用开发与系统底层开发。你可以参考这份资料,少走很多弯路,节省没必要的麻烦。由两位前阿里高级研发工程师联合打造的《鸿蒙NEXT星河版OpenHarmony开发文档》里面内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(Harmony NEXT)技术知识点

如果你是一名Android、Java、前端等等开发人员,想要转入鸿蒙方向发展。可以直接领取这份资料辅助你的学习。下面是鸿蒙开发的学习路线图。

在这里插入图片描述

针对鸿蒙成长路线打造的鸿蒙学习文档。话不多说,我们直接看详细鸿蒙(OpenHarmony )手册(共计1236页)与鸿蒙(OpenHarmony )开发入门视频,帮助大家在技术的道路上更进一步。

  • 《鸿蒙 (OpenHarmony)开发学习视频》
  • 《鸿蒙生态应用开发V2.0白皮书》
  • 《鸿蒙 (OpenHarmony)开发基础到实战手册》
  • OpenHarmony北向、南向开发环境搭建
  • 《鸿蒙开发基础》
  • 《鸿蒙开发进阶》
  • 《鸿蒙开发实战》

在这里插入图片描述

总结

鸿蒙—作为国家主力推送的国产操作系统。部分的高校已经取消了安卓课程,从而开设鸿蒙课程;企业纷纷跟进启动了鸿蒙研发。

并且鸿蒙是完全具备无与伦比的机遇和潜力的;预计到年底将有 5,000 款的应用完成原生鸿蒙开发,未来将会支持 50 万款的应用。那么这么多的应用需要开发,也就意味着需要有更多的鸿蒙人才。鸿蒙开发工程师也将会迎来爆发式的增长,学习鸿蒙势在必行! 自↓↓↓拿

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

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

相关文章

pytest:4种方法实现 - 重复执行用例 - 展示迭代次数

简介&#xff1a;在软件测试中&#xff0c;我们经常需要重复执行测试用例&#xff0c;以确保代码的稳定性和可靠性。在本文中&#xff0c;我们将介绍四种方法来实现重复执行测试用例&#xff0c;并显示当前迭代次数和剩余执行次数。这些方法将帮助你更好地追踪测试执行过程&…

3.多租户调研1

https://gitee.com/xiaoqiangBUG/hello-ruoyi-cloud.git 1.mybatis plus 的插件 TenantLineInnerInterceptor 是 MyBatis Plus 框架中的一个拦截器&#xff0c;它用于实现多租户系统的数据隔离。在多租户应用中&#xff0c;不同的租户应该只能访问到自己的数据&#xff0c;而…

URL过滤、DNS过滤和内容过滤的总结

目录 URL过滤 URL和URI URL -- 统一资源定位符 URI --- 统一资源的标识符 URL和URI之间的区别 URL过滤的方式 HTTP协议获取URL的方式 HTTP协议做控制管理的流程 HTTPS协议做控制管理的流程 1&#xff0c;配置SSL的解密功能 2&#xff0c;直接针对加密流量进行过滤 例…

javaEE-03-cookie与session

文章目录 Cookie创建Cookie获取Cookie更新CookieCookie 生命控制Cookie 有效路径 Session 会话创建和获取sessionSession 域数据的存取Session 生命周期控制浏览器和 Session 之间关联 Cookie Cookie 是服务器通知客户端保存键值对的一种技术,客户端有了 Cookie 后&#xff0c…

深入解析 GPT-4o mini:强大功能与创新应用

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文由 JohnKi 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f4e2;未来很长&#…

品牌故事线:如何在活动策划中保持品牌信息的连贯性?

在活动运营中保持品牌一致性和传达清晰的品牌信息&#xff0c;是确保活动成功并提升品牌形象的关键。 以下是一些具体的方法和建议。 码字不易&#xff0c;如果回答对你有所帮助&#xff0c;请不吝给一个三连哦&#xff01; 一、明确品牌定位与核心价值 首先&#xff0c;需…

一起刷C语言菜鸟教程100题(27-35)

先说明这个虽然菜鸟教程也有答案&#xff0c;但是这个专栏的博客是自己过手写了一遍&#xff0c;有自己的理解&#xff0c;有些习题自己是变化了一些&#xff0c;更适合练手&#xff0c;也会写的更普遍一些~ 今天我们一起继续刷题&#xff0c;链接放在这里供大家自行使用 C 语…

小红书(社招二面)算法原题

萝卜快跑涨价 距离我们上次谈 萝卜快跑 不足半月&#xff0c;萝卜快跑迎来了不少"反转"。 先是被曝远程后台有人操控&#xff0c;真实日成本超 400&#xff1a; 最近还被不少网友吐槽&#xff1a;萝卜快跑涨价了&#xff0c;如今价格和网约车持平。 据不少博主实测&a…

如何在 Windows 上安装并配置 VNC 远程连接树莓派,并结合Cpolar实现公网远程访问

目录 ⛳️推荐 前言 1. 使用 Raspberry Pi Imager 安装 Raspberry Pi OS 2. Windows安装VNC远程树莓派 3. 使用VNC Viewer公网远程访问树莓派 3.1 安装Cpolar步骤 3.2 配置固定的公网地址 3.3 VNC远程连接测试 4. 固定远程连接公网地址 4.1 固定TCP地址测试 ⛳️推荐…

FastAPI(六十九)实战开发《在线课程学习系统》接口开发--修改密码

源码见&#xff1a;"fastapi_study_road-learning_system_online_courses: fastapi框架实战之--在线课程学习系统" 之前我们分享了FastAPI&#xff08;六十八&#xff09;实战开发《在线课程学习系统》接口开发--用户 个人信息接口开发。这次我们去分享实战开发《在线…

【Linux操作系统】:进程间通信

目录 进程间通信介绍 1、进程间通信的概念 2、进程间通信的目的 3、进程间通信的本质 4、进程间通信的分类 管道 匿名管道 匿名管道的原理 pipe函数 创建匿名管道 管道的四种情况和五种特性 命名管道 使用命令创建命名管道 创建一个命名管道 命名管道的打开规则 …

Lc60---1189. “气球” 的最大数量(排序)---Java版

1.题目 2.思路 (1)用字典的方法,ballon,这个单词里面每个字母&#xff0c;需要的个数 (2)再创一个字典的方法统计&#xff0c;输入的字符串的字母的个数 (3)计算能拼凑出多少个“ballon" (4)代码解释 for (char c : text.toCharArray()) {count.put(c, count.getOrDefau…

【C++ —— AVL树】

C —— AVL树 AVL树的概念AVL树节点的定义AVL树的插入向上调整旋转左单旋右单旋左右双旋右左双旋 AVL树的高度AVL树的验证总结&#xff1a;代码 AVL树的概念 二叉搜索树虽可以缩短查找的效率&#xff0c;但如果数据有序或接近有序二叉搜索树将退化为单支树&#xff0c;查找元素…

在QT中使用多线程并发服务器(C++)

什么是多线程并发服务器&#xff1f;在QT里如何使用多线程并发服务器呢&#xff1f; 多线程并发服务器是一种网络服务器设计&#xff0c;它能够同时处理多个客户端的请求。在多线程服务器中&#xff0c;主线程负责监听和接受来自客户端的连接请求&#xff0c;每当有一个新的连…

DNS服务器的搭建

1、DNS服务器端软件 DNS 的域名解析都是 udp/53 . 主从之间的数据传输默认使 ⽤tcp/53 DNS服务器端软件&#xff1a; Bind是⼀款开放源码的DNS服务器软件&#xff0c;Bind由美国加州⼤学Berkeley&#xff08;伯克 利&#xff09;分校开发和维护的&#xff0c;全名为Berkele…

美容院如何提高门店销售业绩?博弈美业收银系统分享五大策略

美容院要如何增加门店业绩&#xff1f;各位老板可以考虑以下几个方面的策略&#xff1a; 一、品牌宣传和营销&#xff1a; • 制定全面的营销计划&#xff0c;包括线上和线下宣传。可以利用社交媒体、网站、本地广告等多种渠道提升品牌知名度。 • 开展促销活动吸引新客户&a…

PYTHON学习笔记(七、python数据结构--集合)

目录 &#xff08;4&#xff09;set集合 1、集合的创建方式 1&#xff09;使用{ }直接创建集合 2&#xff09;使用内置函数set( )创建集合 3&#xff09;使用“ 集合生成式 ”生成集合 2、集合的访问方式 1&#xff09;使用for循环遍历 3、集合的修改操作 4、集合的…

SvelteKit - 1. 初始化项目

官方 doc - create a project 1、基本环境 &#xff08;下面是我这里的环境&#xff0c;亲测用 node 14 和 16 install 会报错&#xff09; node&#xff1a;20.9.0 npm&#xff1a;10.1.0 2、初始化项目 npm create sveltelatest my-app cd my-app npm install npm run de…

本地部署、微调大模型

本地部署、微调大模型 一、本地部署大模型 1.部署 更新git-lfs apt-get updateapt-get install git-lfs2. 这里极容易出错&#xff0c;如果报错就初始化git git lfs install git init git lfs install3.下载ChatGLM-6B源代码 git clone https://github.com/THUDM/ChatGLM…

华为强制恢复出厂设置后如何恢复数据?数据重生的2个方法介绍

华为作为全球知名的手机品牌&#xff0c;其产品在市场上广受欢迎。然而&#xff0c;有时由于各种原因&#xff0c;我们可能需要强制恢复出厂设置&#xff0c;这往往意味着数据的丢失。那么&#xff0c;如何在华为强制恢复出厂设置后&#xff0c;让数据“重生”呢&#xff1f;本…