加密和解密(1):常⽤数据加密和解密⽅法汇总
数据加密技术是⽹络中最基本的安全技术,主要是通过对⽹络中传输的信息进⾏数据加密来保障其安全性,这是⼀种主动安全防御策略,⽤很⼩的代价即可为信息提供相
当⼤的安全保护。
⼀、加密的基本概念
"加密",是⼀种限制对⽹络上传输数据的访问权的技术。原始数据(也称为明⽂,plaintext)被加密设备(硬件或软件)和密钥加密⽽产⽣的经过编码的数据称为密⽂
(ciphertext)。将密⽂还原为原始明⽂的过程称为解密,它是加密的反向处理,但解密者必须利⽤相同类型的加密设备和密钥对密⽂进⾏解密。
加密的基本功能包括:
1. 防⽌不速之客查看机密的数据⽂件;
2. 防⽌机密数据被泄露或篡改;
3. 防⽌特权⽤户(如系统管理员)查看私⼈数据⽂件;
4. 使⼊侵者不能轻易地查找⼀个系统的⽂件。
数据加密是确保计算机⽹络安全的⼀种重要机制,虽然由于成本、技术和管理上的复杂性等原因,⽬前尚未在⽹络中普及,但数据加密的确是实现分布式系统和⽹络环境下
数据安全的重要⼿段之⼀。
数据加密可在⽹络OSI七层协议(OSI是Open System Interconnect的缩写,意为开放式系统互联。国际标准组织(国际标准化组织)制定了OSI模型。这个模型把⽹络通信
的⼯作分为7层,分别是物理层、数据链路层、⽹络层、传输层、会话层、表⽰层和应⽤层。)的多层上实现、所以从加密技术应⽤的逻辑位置看,有三种⽅式:
①链路加密:通常把⽹络层以下的加密叫链路加密,主要⽤于保护通信节点间传输的数据,加解密由置于线路上的密码设备实现。根据传递的数据的同步⽅式⼜可分为同步
通信加密和异步通信加密两种,同步通信加密⼜包含字节同步通信加密和位同步通信加密。
②节点加密:是对链路加密的改进。在协议传输层上进⾏加密,主要是对源节点和⽬标节点之间传输数据进⾏加密保护,与链路加密类似.只是加密算法要结合在依附于节点
的加密模件中,克服了链路加密在节点处易遭⾮法存取的缺点。
③端对端加密:⽹络层以上的加密称为端对端加密。是⾯向⽹络层主体。对应⽤层的数据信息进⾏加密,易于⽤软件实现,且成本低,但密钥管理问题困难,主要适合⼤型
⽹络系统中信息在多个发⽅和收⽅之间传输的情况。
⼆、数据加密的应⽤
1、 媒体加密:DRM
2、 ⽂件加密:⽂本加密、pdf、word
3、 数据加密:(C#)中的数据加密
4、 硬件加密:加密狗
三.加密技术发展趋势
①私⽤密钥加密技术与公开密钥加密技术相结合:鉴于两种密码体制加密的特点,在实际应⽤中可以采⽤折衷⽅案,即结合使⽤DES/IDEA和RSA,以DES为"内核",RSA
为"外壳",对于⽹络中传输的数据可⽤DES或IDEA加密,⽽加密⽤的密钥则⽤RSA加密传送,此种⽅法既保证了数据安全⼜提⾼了加密和解密的速度,这也是⽬前加密技术
发展的新⽅向之⼀。
②寻求新算法:跳出以常见的迭代为基础的构造思路,脱离基于某些数学问题复杂性的构造⽅法。如刘尊全先⽣提出的刘⽒算法,是⼀种基于密钥的公开密钥体制,它采⽤了
随机性原理构造加解密变换,并将其全部运算控制隐匿于密钥中,密钥长度可变。它是采⽤选取⼀定长度的分割来构造⼤的搜索空间,从⽽实现⼀次⾮线性变换。此种加密
算法加密强度⾼、速度快、计算开销低。
③加密最终将被集成到系统和⽹络中,例如IPV6协议就已有了内置加密的⽀持,在硬件⽅⾯,Intel公司正研制⼀种加密协处理器。它可以集成到微机的主极上。
四、加密技术的分类
加密类型可以简单地分为四种:
1. 根本不考虑解密问题;
2. 私⽤密钥加密技术:对称式加密(Symmetric Key Encryption):对称式加密⽅式对加密和解密使⽤相同的密钥。通常,这种加密⽅式在应⽤中难以实施,因为⽤同⼀种
安全⽅式共享密钥很难。如:RC4、RC2、DES 和 AES 系列加密算法。
3. 公开密钥加密技术:⾮对称密钥加密(Asymmetric Key Encryption):⾮对称密钥加密使⽤⼀组公共/私⼈密钥系统,加密时使⽤⼀种密钥,解密时使⽤另⼀种密钥。公
共密钥可以⼴泛的共享和透露。当需要⽤加密⽅式向服务器外部传送数据时,这种加密⽅式更⽅便。如: RSA
4. 数字证书。(Certificate):数字证书是⼀种⾮对称密钥加密,但是,⼀个组织可以使⽤证书并通过数字签名将⼀组公钥和私钥与其拥有者相关联。
五、对称加密之DES加密与解密
1、 对称加密
对称加密,是⼀种⽐较传统的加密⽅式,其加密运算、解密运算使⽤的是同样的密钥,信息的发送者和信息的接收者在进⾏信息的传输与处理时,必须共同持有该密码(称
为对称密码)。因此,通信双⽅都必须获得这把钥匙,并保持钥匙的秘密。
单钥密码系统的安全性依赖于以下两个因素:
第⼀、加密算法必须是⾜够强的,仅仅基于密⽂本⾝去解密信息在实践上是不可能的。
第⼆、加密⽅法的安全性依赖于密钥的秘密性,⽽不是算法的秘密性,因此,我们没有必要确保算法的秘密性(事实上,现实中使⽤的很多单钥密码系统的算法都是公开
的),但是我们⼀定要保证密钥的秘密性。
DES(Data Encryption Standard)和TripleDES是对称加密的两种实现。
DES和TripleDES基本算法⼀致,只是TripleDES算法提供的key位数更多,加密可靠性更⾼。
DES使⽤的密钥key为8字节,初始向量IV也是8字节。
TripleDES使⽤24字节的key,初始向量IV也是8字节。
两种算法都是以8字节为⼀个块进⾏加密,⼀个数据块⼀个数据块的加密,⼀个8字节的明⽂加密后的密⽂也是8字节。如果明⽂长度不为8字节的整数倍,添加值为0的字节
凑满8字节整数倍。所以加密后的密⽂长度⼀定为8字节的整数倍。
2、 加密解密过程
Figure 1. DES加密解密过程
上图是整个DES和TripleDES算法的加密解密过程,下⾯以TripleDES为例,结合dotnet分析加密解密的各个步骤,并给出相关实现代码。
1、 ⽣成key和IV
graphy. TripleDESCryptoServiceProvider类是dotnet中实现TripleDES算法的主要的类。
TripleDESCryptoServiceProvider类只有⼀个构造⽅法TripleDESCryptoServiceProvider(),这个⽅法把⼀些属性初始化:
KeySize(加密密钥长度,以位为单位)= 192(24字节)
BlockSize(加密处理的数据块⼤⼩,以位为单位)= 64(8字节)
FeedbackSize(加密数据块后返回的数据⼤⼩,以位为单位)= 64(8字节)
TripleDESCryptoServiceProvider构造⽅法同时会初始化⼀组随机的key和IV。
默认的TripleDESCryptoServiceProvider的key为24字节,IV为8字节,加密数据块为8字节。
⽣成key和IV的代码很简单:
TripleDESCryptoServiceProvider tDESalg = new TripleDESCryptoServiceProvider();
byte[] keyArray = ;
byte[] IVArray = ;
⽣成的key和IV在加密过程和解密过程都要使⽤。
2、 字符串明⽂转成某⼀代码页对应的编码字节流
待加密的数据可能有两种形式,⼀种是⼆进制的数据,本⾝就是⼀组字节流,这样的数据可以跳过这⼀步,直接进⼊加密步骤。还有⼀种情况是字符串数据,字符串中同样
的字符使⽤不同的代码页会⽣成不同的字节码,所以从字符串到字节流的转换是需要指定使⽤何种编码的。在解密之后,要从字节流转换到字符串就要使⽤相同的代码页解
码,否则就会出现乱码。
// 待加密的字符串
string plainTextString = "Here is some data to encrypt. 这⾥是⼀些要加密的数据。";
// 使⽤utf-8编码(也可以使⽤其它的编码)
Encoding sEncoding = oding("utf-8");
// 把字符串明⽂转换成utf-8编码的字节流
byte[] plainTextArray = es(plainTextString);
3、 加密操作
加密的原料是明⽂字节流,TripleDES算法对字节流进⾏加密,返回的是加密后的字节流。同时要给定加密使⽤的key和IV。
// 把字符串明⽂转换成utf-8编码的字节流
byte[] plainTextArray = es(plainTextString);
public static byte[] EncryptString(byte[] plainTextArray, byte[] Key, byte[] IV)
{
// 建⽴⼀个MemoryStream,这⾥⾯存放加密后的数据流
MemoryStream mStream = new MemoryStream();
// 使⽤MemoryStream 和key、IV新建⼀个CryptoStream 对象
CryptoStream cStream = new CryptoStream(mStream,
new TripleDESCryptoServiceProvider().CreateEncryptor(Key, IV),
);
// 将加密后的字节流写⼊到MemoryStream
(plainTextArray, 0, );
//把缓冲区中的最后状态更新到MemoryStream,并清除cStream的缓存区
inalBlock();
// 把解密后的数据流转成字节流
byte[] ret = y();
// 关闭两个streams.
();
();
return ret;
}
4、 解密操作
解密操作解密上⾯步骤⽣成的密⽂byte[],需要使⽤到加密步骤使⽤的同⼀组Key和IV。
// 调⽤解密⽅法,返回已解密数据的byte[]
byte[] finalPlainTextArray = DecryptTextFromMemory(Data, keyArray, IVArray);
public static byte[] DecryptTextFromMemory(byte[] EncryptedDataArray, byte[] Key, byte[] IV)
{
// 建⽴⼀个MemoryStream,这⾥⾯存放加密后的数据流
MemoryStream msDecrypt = new MemoryStream(EncryptedDataArray);
// 使⽤MemoryStream 和key、IV新建⼀个CryptoStream 对象
CryptoStream csDecrypt = new CryptoStream(msDecrypt,
new TripleDESCryptoServiceProvider().CreateDecryptor(Key, IV),
);
// 根据密⽂byte[]的长度(可能⽐加密前的明⽂长),新建⼀个存放解密后明⽂的byte[]
byte[] DecryptDataArray = new byte[];
// 把解密后的数据读⼊到DecryptDataArray
(DecryptDataArray, 0, );
();
();
return DecryptDataArray;
}
有⼀点需要注意,DES加密是以数据块为单位加密的,8个字节⼀个数据块,如果待加密明byte[]的长度不是8字节的整数倍,算法先⽤值为“0”的byte补⾜8个字节,然后进⾏
加密。所以加密后的密⽂长度⼀定是8的整数倍。这样的密⽂解密后如果补了0值的byte,则解密后这些0值的byte依然存在。⽐如上例中要加密的明⽂是:
“Here is some data to encrypt. 这⾥是⼀些要加密的数据。”
转成明⽂byte[]后是66个字节,DES算法就会补上6个0值的byte,补到72个字节。这样加密后再解密回来的密⽂byte[]解码后的字符串就是这样的:
"Here is some data to encrypt. 这⾥是⼀些要加密的数据。000000"
5、 从编码字节流转成字符串明⽂
// 使⽤前⾯定义的Encoding,utf-8的编码把byte[]转成字符串
plainTextString = ing(finalPlainTextArray);
六、⾮对称加密之RSA加密和解密的讲解
RSA公钥加密算法是1977年由Ron Rivest、Adi Shamirh和LenAdleman在(美国⿇省理⼯学院)开发的。RSA取名来⾃开发他们三者的名字。RSA是⽬前最有影响⼒的
公钥加密算法,它能够抵抗到⽬前为⽌已知的所有密码攻击,已被ISO推荐为公钥数据加密标准。RSA算法基于⼀个⼗分简单的数论事实:将两个⼤素数相乘⼗分容易,但
那时想要对其乘积进⾏因式分解却极其困难,因此可以将乘积公开作为加密密钥。RSA算法是第⼀个能同时⽤于加密和数字签名的算法,也易于理解和操作。
RSA是被研究得最⼴泛的公钥算法,从提出到现在已近⼆⼗年,经历了各种攻击的考验,逐渐为⼈们接受,普遍认为是⽬前最优秀的公钥⽅案之⼀。RSA的安全性依赖
于⼤数的因⼦分解,但并没有从理论上证明破译RSA的难度与⼤数分解难度等价。即RSA的重⼤缺陷是⽆法从理论上把握它的保密性能如何,⽽且密码学界多数⼈⼠倾向于
因⼦分解不是NPC问题。
RSA的缺点主要有:
A)产⽣密钥很⿇烦,受到素数产⽣技术的限制,因⽽难以做到⼀次⼀密。
B)分组长度太⼤,为保证安全性,n ⾄少也要 600bits以上,使运算代价很⾼,尤其是速度较慢,较对称密码算法慢⼏个数量级;且随着⼤数分解技术的发展,这个
长度还在增加,不利于数据格式的标准化。⽬前,SET(Secure Electronic Transaction)协议中要求CA采⽤2048bits长的密钥,其他实体使⽤1024⽐特的密钥。C)RSA密钥
长度随着保密级别提⾼,增加很快。下表列出了对同⼀安全级别所对应的密钥长度。
保密级别对称密钥长度(bit)RSA密钥长度(bit)ECC密钥长度(bit)保密年限
808010241602010
11211220482242030
12812830722562040
19219276803842080
256256153605122120
这种算法1978年就出现了,它是第⼀个既能⽤于数据加密也能⽤于数字签名的算法。它易于理解和操作,也很流⾏。算法的名字以发明者的名字命名:Ron Rivest,
AdiShamir 和Leonard Adleman。早在1973年,英国国家通信总局的数学家Clifford Cocks就发现了类似的算法。但是他的发现被列为绝密,直到1998年才公诸于世。
RSA算法是⼀种⾮对称密码算法,所谓⾮对称,就是指该算法需要⼀对密钥,使⽤其中⼀个加密,则需要⽤另⼀个才能解密。
RSA的算法涉及三个参数,n、e1、e2。
其中,n是两个⼤质数p、q的积,n的⼆进制表⽰时所占⽤的位数,就是所谓的密钥长度。
e1和e2是⼀对相关的值,e1可以任意取,但要求e1与(p-1)*(q-1)互质;再选择e2,要求(e2*e1)mod((p-1)*(q-1))=1。
(n及e1),(n及e2)就是密钥对。
RSA加解密的算法完全相同,设A为明⽂,B为密⽂,则:A=B^e1 mod n;B=A^e2 mod n;
e1和e2可以互换使⽤,即:
A=B^e2 mod n;B=A^e1 mod n;
C#代码实现
需引⽤using graphy;
///
/// RSA加密
///
///
///
///
public static string RSAEncrypt(string publickey, string content)
{
publickey = @"
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
byte[] cipherbytes;
lString(publickey);
cipherbytes = t(es(content), fal);
return 64String(cipherbytes);
}
/// <summary>
/// RSA解密 /// </summary>
/// <param name="privatekey"></param>
/// <param name="content"></param>
/// <returns></returns>
public static { privatekey = @"<RSAKeyValue><Modulus>5m9 RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); byte[] cipherbytes; lString(privatekey); cipherbytes = t(64String(content), fal); return ing(cipherbytes); }
七、(C#)常⽤加密类调⽤的讲解
1、C#常⽤加密解密类库代码如下:
///
/// MD5 加密静态⽅法
///
/// 待加密的密⽂
///
public static string MD5Encrypt(string EncryptString)
{
if (string.IsNullOrEmpty(EncryptString)) { throw (new Exception("密⽂不得为空")); }
MD5 m_ClassMD5 = new MD5CryptoServiceProvider();
string m_strEncrypt = "";
try
{
m_strEncrypt = ng(m_eHash(es(EncryptString))).Replace("-", "");
}
catch (ArgumentException ex) { throw ex; }
catch (CryptographicException ex) { throw ex; }
catch (Exception ex) { throw ex; }
finally { m_(); }
return m_strEncrypt;
}
/// <summary>
/// DES 加密(数据加密标准,速度较快,适⽤于加密⼤量数据的场合 /// </summary>
/// </summary>
/// <param name="EncryptString"> /// <param name="EncryptKey">/// <returns>public static s { if (string.IsNullOrEmpty(EncryptString)) { if (string.IsNullOrEmpty(EncryptKey)) { if ( != 8) { byte[] m_btIV = { 0x12, string m_strEncrypt = ""new DESCryptoServiceProvider try { byte[] m_btEncryptString = es(EncryptString); MemoryStream m_stream = new MemoryStream(); CryptoStream m_cstream = new CryptoStream(m_stream, m_DESProvider m_(m_btEncryptString, 0, m_); m_inalBlock(); m_strEncrypt = 64String(m_y()); m_(); m_e(); m_(); m_e(); } catch (IOException ex) { throwcatch (CryptographicException ex) { throw catch (ArgumentException ex) { throwcatch (Exception ex) { throwfinally { m_(); } return m_strEncrypt; } /// <summary> /// DES 解密(数据加密标准,速度较快,适⽤于加密⼤量数据的场合 /// </summary> /// <param name="DecryptString"> /// <param name="DecryptKey">/// <returns>public static s { if (string.IsNullOrEmpty(DecryptString)) { if (string.IsNullOrEmpty(DecryptKey)) { if ( != 8) { byte[] m_btIV = { 0x12, string m_strDecrypt = ""new DESCryptoServiceProvider try { byte[] m_btDecryptString = 64String(DecryptString); MemoryStream m_stream = new MemoryStream(); CryptoStream m_cstream = new CryptoStream(m_stream, m_DESProvider. m_(m_btDecryptString, 0, m_); m_inalBlock(); m_strDecrypt = ing(m_y()); m_(); m_e(); m_(); m_e(); } catch (IOException ex) { throwcatch (CryptographicException ex) { throw catch (ArgumentException ex) { throwcatch (Exception ex) { throwfinally { m_(); } return m_strDecrypt; } /// <summary> /// RC2 加密(⽤变长密钥对⼤量数据进⾏加密) /// </summary> /// <param name="EncryptString">/// <param name="EncryptKey">/// <returns>public static s { if (string.IsNullOrEmpty(EncryptString)) { if (string.IsNullOrEmpty(EncryptKey)) { if ( < 5 || string m_strEncrypt = ""byte[] m_btIV = { 0x12, byte[] m_btIV = { 0x12, new RC2CryptoServiceProvider() try { byte[] m_btEncryptString = es(EncryptString); MemoryStream m_stream = new MemoryStream(); CryptoStream m_cstream = new CryptoStream(m_stream, m_RC2Provider. m_(m_btEncryptString, 0, m_); m_inalBlock(); m_strEncrypt = 64String(m_y()); m_(); m_e(); m_(); m_e(); } catch (IOException ex) { throwcatch (CryptographicException ex) { throw catch (ArgumentException ex) { throwcatch (Exception ex) { throwfinally { m_(); } return m_strEncrypt; } /// <summary> /// RC2 解密(⽤变长密钥对⼤量数据进⾏加密) /// </summary> /// <param name="DecryptString">/// <param name="DecryptKey">/// <returns>public static s { if (string.IsNullOrEmpty(DecryptString)) { if (string.IsNullOrEmpty(DecryptKey)) { if ( < 5 || byte[] m_btIV = { 0x12, string m_strDecrypt = ""new RC2CryptoServiceProvider() try { byte[] m_btDecryptString = 64String(DecryptString); MemoryStream m_stream = new MemoryStream(); CryptoStream m_cstream = new CryptoStream(m_stream, m_RC2Provider. m_(m_btDecryptString, 0, m_); m_inalBlock(); m_strDecrypt = ing(m_y()); m_(); m_e(); m_(); m_e(); } catch (IOException ex) { throwcatch (CryptographicException ex) { throw catch (ArgumentException ex) { throwcatch (Exception ex) { throwfinally { m_(); } return m_strDecrypt; } /// <summary> /// 3DES 加密(基于DES,对⼀块数据⽤三个不同的密钥进⾏三次加 /// </summary> /// <param name="EncryptString">/// <param name="EncryptKey1">/// <param name="EncryptKey2">/// <param name="EncryptKey3">/// <returns>public static s { string m_strEncrypt = ""try { m_strEncrypt = DESEncrypt(EncryptString, EncryptKey3); m_strEncrypt = DESEncrypt(m_strEncrypt, EncryptKey2); m_strEncrypt = DESEncrypt(m_strEncrypt, EncryptKey1); } catch (Exception ex) { throwreturn m_strEncrypt; } /// <summary> /// 3DES 解密(基于DES,对⼀块数据⽤三个不同的密钥进⾏三次加 /// 3DES 解密(基于DES,对⼀块数据⽤三个不同的密钥进⾏三次加 /// </summary> /// <param name="DecryptString">/// <param name="DecryptKey1">/// <param name="DecryptKey2">/// <param name="DecryptKey3">/// <returns>public static s { string m_strDecrypt = ""try { m_strDecrypt = DESDecrypt(DecryptString, DecryptKey1); m_strDecrypt = DESDecrypt(m_strDecrypt, DecryptKey2); m_strDecrypt = DESDecrypt(m_strDecrypt, DecryptKey3); } catch (Exception ex) { throwreturn m_strDecrypt; } /// <summary> /// AES 加密(⾼级加密标准,是下⼀代的加密算法标准,速度快,安 /// </summary> /// <param name="EncryptString">/// <param name="EncryptKey">/// <returns></returns> public static st { if (string.IsNullOrEmpty(EncryptString)) { if (string.IsNullOrEmpty(EncryptKey)) { string m_strEncrypt = ""byte[] m_btIV = 64String(" Rijndael m_AESProvider = (); try { byte[] m_btEncryptString = es(EncryptString); MemoryStream m_stream = new MemoryStream(); CryptoStream m_csstream = new CryptoStream(m_stream, m_AESProvide m_(m_btEncryptString, 0, m_); m_c m_strEncrypt = 64String(m_y()); m_(); m_e(); m_(); m_e(); } catch (IOException ex) { throwcatch (CryptographicException ex) { throw catch (ArgumentException ex) { throwcatch (Exception ex) { throwfinally { m_(); } return m_strEncrypt; } /// <summary> /// AES 解密(⾼级加密标准,是下⼀代的加密算法标准,速度快,安 /// </summary> /// <param name="DecryptString">/// <param name="DecryptKey">/// <returns></returns> public static s { if (string.IsNullOrEmpty(DecryptString)) { if (string.IsNullOrEmpty(DecryptKey)) { string m_strDecrypt = ""byte[] m_btIV = 64String(" Rijndael m_AESProvider = (); try { byte[] m_btDecryptString = 64String(DecryptString); MemoryStream m_stream = new MemoryStream(); CryptoStream m_csstream = new CryptoStream(m_stream, m_AESProvide m_(m_btDecryptString, 0, m_); m_c m_strDecrypt = ing(m_y()); m_(); m_e(); m_(); m_e(); } catch (IOException ex) { throwcatch (CryptographicException ex) { throw catch (CryptographicException ex) { throw catch (ArgumentException ex) { throwcatch (Exception ex) { throwfinally { m_(); } return m_strDecrypt; } 2、数据加密和解密简单代码调⽤如下: (" (5Encrypt("仰天⼀笑")); (" (rypt("仰天⼀笑", "anson-xu")); (" (rypt("l06JvJ45r/lb9iKzSXl47Q==", "anson-xu")); (" (rypt("仰天⼀笑", "ansonxuyu")); (" (rypt("avwKL+MO8+zoLHvzk0+TBA==", "ansonxuyu")); 3、数据加密和解密调⽤后运⾏效果图如下: 注:本篇为转载的⽂章!
-----------MD5加密---------------
");
-----------DES加密---------------
");
-----------DES解密---------------
");
-----------AES加密---------------
");
-----------AES解密---------------
");
本文发布于:2023-05-23 06:36:41,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/zhishi/a/1684795002174918.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文word下载地址:加密和解密(1):常用数据加密和解密方法汇总.doc
本文 PDF 下载地址:加密和解密(1):常用数据加密和解密方法汇总.pdf
留言与评论(共有 0 条评论) |