OT 安全和IEC62443标準
與IT相比,工業控制系統(ICS)的安全性也稱為OT安全性,它始于諸如電力,天然氣和水等關鍵基礎設施。随着向開放系統的發展以及與IIoT和工業4.0趨勢一緻的威脅變化,各個領域的工作正全面展開。據說Stuxnet在2010年成為了全球觸發者。在過去的十年中,各個國家和行業都積極制定了指南和架構,但是它們似乎缺乏連貫性。最近,已經整合了多個指南,可以說作為全球标準的兩個引人注目的标準是IEC62443。從智能工廠的安全性角度來看,還有NIST CSF,SP800系列。
IEC 62443。這個标準是ISA99和IEC委員會共同開發的。IEC62443是一組14個文檔,提供了通用工業控制系統(IACS:在本标準中稱為工業自動化控制系統)的安全技術規範。該标準是由國際自動化學會(ISA)和國際電工委員會(IEC)制定的,迄今為止已釋出14個文檔中的8個,并且正在進行修訂和開發。我粗略地看了一下,好像蠻複雜的樣子。
資訊安全的基本知識
結合IEC61499 分布式功能塊技術,最近通過協定分析,發現施耐德公司EAE 中底層協定使用了websocket,hash 摘要和加密資料等。估計EAE采用的還是相對簡單的,hash 數字摘要+AES對稱加密,是否有證書機制,沒有看出來。AES 的加密key 也不知道。按說,作為一個開放性系統,加密方式也需要Open 的。要不然,不同廠商額裝置和軟體工具無法相容。
在這裡,了解一些關于openSSL,TLS 基本的資訊安全技術。為IEC61499 安全平台做一些準備工作。
資訊安全問題
在資訊安全性問題中,我們常常要做到三點才能保證資訊的安全:
- 資訊的保密性
- 資訊的完整性
- 身份識别
SSL(Secure Socket Layer)代表安全套接字層,而TLS(Transport Layer Security)代表傳輸層安全性。安全套接字層和傳輸層安全性都是用于在Web浏覽器和Web伺服器之間提供安全性的協定。
三項基礎技術
散列函數Hash
常見的有 MD5、SHA1、SHA256,該類函數特點是函數單向不可逆、對輸入非常敏感、輸出長度固定,針對資料的任何修改都會改變散列函數的結果,用于防止資訊篡改并驗證資料的完整性;
在資訊傳輸過程中,散列函數不能單獨實作資訊防篡改,因為明文傳輸,中間人可以修改資訊之後重新計算資訊摘要,是以需要對傳輸的資訊以及資訊摘要進行加密;
hash 函數産生的hash 值稱為文本的數字摘要。如果接收端計算出來的數字摘要和發送端發送來的數字摘要是一緻的,說明資料是完整的沒有被修改。這有點類似于CRC 校驗碼,隻是當文本很長的時候,簡單地使用CRC 碼無法完全判斷文本是否完整。
Go 程式
package main
import "crypto/sha1"
import "fmt"
func main() {
s := "Hello 8gwifi.org"
// The pattern for generating a hash is `sha1.New()`,
// `sha1.Write(bytes)`, then `sha1.Sum([]byte{})`.
// Here we start with a new hash.
h := sha1.New()
// `Write` expects bytes. If you have a string `s`,
// use `[]byte(s)` to coerce it to bytes.
h.Write([]byte(s))
// This gets the finalized hash result as a byte
// slice. The argument to `Sum` can be used to append
// to an existing byte slice: it usually isn't needed.
bs := h.Sum(nil)
// SHA1 values are often printed in hex, for example
// in git commits. Use the `%x` format verb to convert
// a hash results to a hex string.
fmt.Println(s)
fmt.Printf("%x\n", bs)
}
對稱加密
常見的有 AES-CBC、DES、3DES、AES-GCM等,相同的密鑰可以用于資訊的加密和解密,掌握密鑰才能擷取資訊,能夠防止資訊竊聽,通信方式是1對1;
對稱加密的優勢是資訊傳輸1對1,需要共享相同的密碼,密碼的安全是保證資訊安全的基礎,伺服器和 N 個用戶端通信,需要維持 N 個密碼記錄,且缺少修改密碼的機制;
對稱加密的例子,參考下列位址
Go Encryption and Decryption using AES - Tutorial
加密程式
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"fmt"
"io/ioutil"
"io"
)
func main() {
fmt.Println("Encryption Program v0.01")
text := []byte("My Super Secret Code Stuff")
key := []byte("passphrasewhichneedstobe32bytes!")
// generate a new aes cipher using our 32 byte long key
c, err := aes.NewCipher(key)
// if there are any errors, handle them
if err != nil {
fmt.Println(err)
}
// gcm or Galois/Counter Mode, is a mode of operation
// for symmetric key cryptographic block ciphers
// - https://en.wikipedia.org/wiki/Galois/Counter_Mode
gcm, err := cipher.NewGCM(c)
// if any error generating new GCM
// handle them
if err != nil {
fmt.Println(err)
}
// creates a new byte array the size of the nonce
// which must be passed to Seal
nonce := make([]byte, gcm.NonceSize())
// populates our nonce with a cryptographically secure
// random sequence
if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
fmt.Println(err)
}
// here we encrypt our text using the Seal function
// Seal encrypts and authenticates plaintext, authenticates the
// additional data and appends the result to dst, returning the updated
// slice. The nonce must be NonceSize() bytes long and unique for all
// time, for a given key.
fmt.Println(gcm.Seal(nonce, nonce, text, nil))
// the WriteFile method returns an error if unsuccessful
err = ioutil.WriteFile("myfile.data", gcm.Seal(nonce, nonce, text, nil), 0777)
// handle this error
if err != nil {
// print it out
fmt.Println(err)
}
}
解密程式
package main
import (
"crypto/aes"
"crypto/cipher"
"fmt"
"io/ioutil"
)
func main() {
fmt.Println("Decryption Program v0.01")
key := []byte("passphrasewhichneedstobe32bytes!")
ciphertext, err := ioutil.ReadFile("./myfile.data")
// if our program was unable to read the file
// print out the reason why it can't
if err != nil {
fmt.Println(err)
}
c, err := aes.NewCipher(key)
if err != nil {
fmt.Println(err)
}
gcm, err := cipher.NewGCM(c)
if err != nil {
fmt.Println(err)
}
nonceSize := gcm.NonceSize()
if len(ciphertext) < nonceSize {
fmt.Println(err)
}
nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
fmt.Println(err)
}
fmt.Println(string(plaintext))
}
非對稱加密
即常見的 RSA 算法,還包括 ECC、DH 等算法,算法特點是,密鑰成對出現,一般稱為公鑰(公開)和私鑰(保密),公鑰加密的資訊隻能私鑰解開,私鑰加密的資訊隻能公鑰解開。是以掌握公鑰的不同用戶端之間不能互相解密資訊,隻能和掌握私鑰的伺服器進行加密通信,伺服器可以實作1對多的通信,用戶端也可以用來驗證掌握私鑰的伺服器身份。
非對稱加密的特點是資訊傳輸1對多,伺服器隻需要維持一個私鑰就能夠和多個用戶端進行加密通信,但伺服器發出的資訊能夠被所有的用戶端解密,且該算法的計算複雜,加密速度慢。
非對稱加密算法比對稱加密算法要複雜的多,處理起來也要慢得多。如果所有的網絡資料都用非對稱加密算法來加密,那效率會很低。是以在實際中,非對稱加密隻會用來傳遞一條資訊,那就是用于對稱加密的密鑰。當用于對稱加密的密鑰确定了,A和B還是通過對稱加密算法進行網絡通信。這樣,既保證了網絡通信的安全性,又不影響效率,A和B也不用見面商量密鑰了。
加/解密主要步驟
是以,在現代,A和B之間要進行安全,省心的網絡通信,需要經過以下幾個步驟
- 通過CA體系交換public key
- 通過非對稱加密算法,交換用于對稱加密的密鑰
- 通過對稱加密算法,加密正常的網絡通信
公鑰/私鑰
當用戶端發送請求到服務端的時候,将會收到服務端發送的公鑰,伺服器有對應的私鑰; 服務端與用戶端進行通訊的時候,使用私鑰将資料進行加密傳輸,用戶端使用公鑰進行解密後獲得内容,而用戶端發送資料到服務端的時候會使用公鑰将内容進行加密,伺服器接收後使用私鑰解密。
CA 證書身份識别
在傳輸的過程中,用戶端如何獲得伺服器端的公鑰呢?當時是伺服器分發給用戶端,如果一開始服務端發送的公鑰到用戶端的過程中有可能被第三方劫持,然後第三方自己僞造一對密鑰,将公鑰發送給用戶端,當伺服器發送資料給用戶端的時候,中間人将資訊進行劫持,用一開始劫持的公鑰進行解密後,然後使用自己的私鑰将資料加密發送給用戶端,而用戶端收到後使用公鑰解密,反過來亦是如此,整個過程中間人是透明的,但資訊洩露卻不得而知。
伺服器端生成私鑰
openssl genrsa -out server.key 2048
伺服器端生成證書
openssl req -new -x509 -key server.key -out server.pem -days 3650
Golang TLS 伺服器/用戶端
伺服器端
package main
import (
"bufio"
"crypto/tls"
"log"
"net"
)
func main() {
cert, err := tls.LoadX509KeyPair("server.pem", "server.key")
if err != nil {
log.Println(err)
return
}
config := &tls.Config{Certificates: []tls.Certificate{cert}}
ln, err := tls.Listen("tcp", ":443", config)
if err != nil {
log.Println(err)
return
}
defer ln.Close()
for {
conn, err := ln.Accept()
if err != nil {
log.Println(err)
continue
}
go handleConn(conn)
}
}
func handleConn(conn net.Conn) {
defer conn.Close()
r := bufio.NewReader(conn)
for {
msg, err := r.ReadString('\n')
if err != nil {
log.Println(err)
return
}
println(msg)
n, err := conn.Write([]byte("World\n"))
if err != nil {
log.Println(n, err)
return
}
}
}
用戶端
func main() {
conf := &tls.Config{
InsecureSkipVerify: true,
}
conn, err := tls.Dial("tcp", "127.0.0.1:443", conf)
if err != nil {
log.Println(err)
return
}
defer conn.Close()
n, err := conn.Write([]byte("Hello\n"))
if err != nil {
log.Println(n, err)
return
}
buf := make([]byte, 100)
n, err = conn.Read(buf)
if err != nil {
log.Println(n, err)
return
}
println(string(buf[:n]))
}
Crypto++® 庫
crypto++ 是一個·C++ 的加密庫。網站位址:https://www.cryptopp.com/
它支援下列算法:
Algorithm | Name |
---|---|
authenticated encryption schemes | GCM, CCM, EAX, ChaCha20Poly1305, XChaCha20Poly1305 |
high speed stream ciphers | ChaCha (8/12/20), ChaCha (IETF) HC (128/256), Panama, Rabbit (128/256), Sosemanuk, Salsa20 (8/12/20), XChaCha (8/12/20), XSalsa20 |
AES and AES candidates | AES (Rijndael), RC6, MARS, Twofish, Serpent, CAST-256 |
other block ciphers | ARIA, Blowfish, Camellia, CHAM, HIGHT, IDEA, Kalyna (128/256/512), LEA, SEED, RC5, SHACAL-2, SIMECK, SIMON (64/128), Skipjack, SPECK (64/128), Simeck, SM4,Threefish (256/512/1024), Triple-DES (DES-EDE2 and DES-EDE3), TEA, XTEA |
block cipher modes of operation | ECB, CBC, CBC ciphertext stealing (CTS), CFB, OFB, counter mode (CTR), XTS |
message authentication codes | BLAKE2b, BLAKE2s, CMAC, CBC-MAC, DMAC, GMAC (GCM), HMAC, Poly1305, SipHash, Two-Track-MAC, VMAC |
hash functions | BLAKE2b, BLAKE2s, Keccack (F1600), SHA-1, SHA-2, SHA-3, SHAKE (128/256), SipHash, Tiger, RIPEMD (128/160/256/320), SM3, WHIRLPOOL |
public-key cryptography | RSA, DSA, Determinsitic DSA (RFC 6979), ElGamal, Nyberg-Rueppel (NR), Rabin-Williams (RW), EC-based German Digital Signature (ECGDSA), LUC, LUCELG, DLIES (variants of DHAES), ESIGN |
padding schemes for public-key systems | PKCS#1 v2.0, OAEP, PSS, PSSR, IEEE P1363 EMSA2 and EMSA5 |
key agreement schemes | Diffie-Hellman (DH), Unified Diffie-Hellman (DH2), Menezes-Qu-Vanstone (MQV), Hashed MQV (HMQV), Fully Hashed MQV (FHMQV), LUCDIF, XTR-DH |
elliptic curve cryptography | ECDSA, Determinsitic ECDSA (RFC 6979), ed25519, ECGDSA, ECNR, ECIES, x25519, ECDH, ECMQV |
insecure or obsolescent algorithms retained for backwards compatibility and historical value | MD2, MD4, MD5, Panama Hash, DES, ARC4, SEAL 3.0, WAKE-OFB, DESX (DES-XEX3), RC2, SAFER, 3-WAY, GOST, SHARK, CAST-128, Square |