ccm_test.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
  2. // SPDX-License-Identifier: MIT
  3. package ccm
  4. // Refer to RFC 3610 section 8 for the vectors.
  5. import (
  6. "bytes"
  7. "crypto/aes"
  8. "encoding/hex"
  9. "errors"
  10. "fmt"
  11. "testing"
  12. )
  13. func mustHexDecode(s string) []byte {
  14. r, err := hex.DecodeString(s)
  15. if err != nil {
  16. panic(err)
  17. }
  18. return r
  19. }
  20. var (
  21. aesKey1to12 = mustHexDecode("c0c1c2c3c4c5c6c7c8c9cacbcccdcecf") //nolint:gochecknoglobals
  22. aesKey13to24 = mustHexDecode("d7828d13b2b0bdc325a76236df93cc6b") //nolint:gochecknoglobals
  23. )
  24. // AESKey: AES Key
  25. // CipherText: Authenticated and encrypted output
  26. // ClearHeaderOctets: Input with X cleartext header octets
  27. // Data: Input with X cleartext header octets
  28. // M: length(CBC-MAC)
  29. // Nonce: Nonce
  30. type vector struct {
  31. AESKey []byte
  32. CipherText []byte
  33. ClearHeaderOctets int
  34. Data []byte
  35. M int
  36. Nonce []byte
  37. }
  38. func TestRFC3610Vectors(t *testing.T) {
  39. cases := []vector{
  40. // Vectors 1-12
  41. {
  42. AESKey: aesKey1to12,
  43. CipherText: mustHexDecode("0001020304050607588c979a61c663d2f066d0c2c0f989806d5f6b61dac38417e8d12cfdf926e0"),
  44. ClearHeaderOctets: 8,
  45. Data: mustHexDecode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e"),
  46. M: 8,
  47. Nonce: mustHexDecode("00000003020100a0a1a2a3a4a5"),
  48. },
  49. {
  50. AESKey: aesKey1to12,
  51. CipherText: mustHexDecode("000102030405060772c91a36e135f8cf291ca894085c87e3cc15c439c9e43a3ba091d56e10400916"),
  52. ClearHeaderOctets: 8,
  53. Data: mustHexDecode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"),
  54. M: 8,
  55. Nonce: mustHexDecode("00000004030201a0a1a2a3a4a5"),
  56. },
  57. {
  58. AESKey: aesKey1to12,
  59. CipherText: mustHexDecode("000102030405060751b1e5f44a197d1da46b0f8e2d282ae871e838bb64da8596574adaa76fbd9fb0c5"),
  60. ClearHeaderOctets: 8,
  61. Data: mustHexDecode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"),
  62. M: 8,
  63. Nonce: mustHexDecode("00000005040302a0a1a2a3a4a5"),
  64. },
  65. {
  66. AESKey: aesKey1to12,
  67. CipherText: mustHexDecode("000102030405060708090a0ba28c6865939a9a79faaa5c4c2a9d4a91cdac8c96c861b9c9e61ef1"),
  68. ClearHeaderOctets: 12,
  69. Data: mustHexDecode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e"),
  70. M: 8,
  71. Nonce: mustHexDecode("00000006050403a0a1a2a3a4a5"),
  72. },
  73. {
  74. AESKey: aesKey1to12,
  75. CipherText: mustHexDecode("000102030405060708090a0bdcf1fb7b5d9e23fb9d4e131253658ad86ebdca3e51e83f077d9c2d93"),
  76. ClearHeaderOctets: 12,
  77. Data: mustHexDecode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"),
  78. M: 8,
  79. Nonce: mustHexDecode("00000007060504a0a1a2a3a4a5"),
  80. },
  81. {
  82. AESKey: aesKey1to12,
  83. CipherText: mustHexDecode("000102030405060708090a0b6fc1b011f006568b5171a42d953d469b2570a4bd87405a0443ac91cb94"),
  84. ClearHeaderOctets: 12,
  85. Data: mustHexDecode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"),
  86. M: 8,
  87. Nonce: mustHexDecode("00000008070605a0a1a2a3a4a5"),
  88. },
  89. {
  90. AESKey: aesKey1to12,
  91. CipherText: mustHexDecode("00010203040506070135d1b2c95f41d5d1d4fec185d166b8094e999dfed96c048c56602c97acbb7490"),
  92. ClearHeaderOctets: 8,
  93. Data: mustHexDecode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e"),
  94. M: 10,
  95. Nonce: mustHexDecode("00000009080706a0a1a2a3a4a5"),
  96. },
  97. {
  98. AESKey: aesKey1to12,
  99. CipherText: mustHexDecode("00010203040506077b75399ac0831dd2f0bbd75879a2fd8f6cae6b6cd9b7db24c17b4433f434963f34b4"),
  100. ClearHeaderOctets: 8,
  101. Data: mustHexDecode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"),
  102. M: 10,
  103. Nonce: mustHexDecode("0000000a090807a0a1a2a3a4a5"),
  104. },
  105. {
  106. AESKey: aesKey1to12,
  107. CipherText: mustHexDecode("000102030405060782531a60cc24945a4b8279181ab5c84df21ce7f9b73f42e197ea9c07e56b5eb17e5f4e"),
  108. ClearHeaderOctets: 8,
  109. Data: mustHexDecode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"),
  110. M: 10,
  111. Nonce: mustHexDecode("0000000b0a0908a0a1a2a3a4a5"),
  112. },
  113. {
  114. AESKey: aesKey1to12,
  115. CipherText: mustHexDecode("000102030405060708090a0b07342594157785152b074098330abb141b947b566aa9406b4d999988dd"),
  116. ClearHeaderOctets: 12,
  117. Data: mustHexDecode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e"),
  118. M: 10,
  119. Nonce: mustHexDecode("0000000c0b0a09a0a1a2a3a4a5"),
  120. },
  121. {
  122. AESKey: aesKey1to12,
  123. CipherText: mustHexDecode("000102030405060708090a0b676bb20380b0e301e8ab79590a396da78b834934f53aa2e9107a8b6c022c"),
  124. ClearHeaderOctets: 12,
  125. Data: mustHexDecode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"),
  126. M: 10,
  127. Nonce: mustHexDecode("0000000d0c0b0aa0a1a2a3a4a5"),
  128. },
  129. {
  130. AESKey: aesKey1to12,
  131. CipherText: mustHexDecode("000102030405060708090a0bc0ffa0d6f05bdb67f24d43a4338d2aa4bed7b20e43cd1aa31662e7ad65d6db"),
  132. ClearHeaderOctets: 12,
  133. Data: mustHexDecode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"),
  134. M: 10,
  135. Nonce: mustHexDecode("0000000e0d0c0ba0a1a2a3a4a5"),
  136. },
  137. // Vectors 13-24
  138. {
  139. AESKey: aesKey13to24,
  140. CipherText: mustHexDecode("0be1a88bace018b14cb97f86a2a4689a877947ab8091ef5386a6ffbdd080f8e78cf7cb0cddd7b3"),
  141. ClearHeaderOctets: 8,
  142. Data: mustHexDecode("0be1a88bace018b108e8cf97d820ea258460e96ad9cf5289054d895ceac47c"),
  143. M: 8,
  144. Nonce: mustHexDecode("00412b4ea9cdbe3c9696766cfa"),
  145. },
  146. {
  147. AESKey: aesKey13to24,
  148. CipherText: mustHexDecode("63018f76dc8a1bcb4ccb1e7ca981befaa0726c55d378061298c85c92814abc33c52ee81d7d77c08a"),
  149. ClearHeaderOctets: 8,
  150. Data: mustHexDecode("63018f76dc8a1bcb9020ea6f91bdd85afa0039ba4baff9bfb79c7028949cd0ec"),
  151. M: 8,
  152. Nonce: mustHexDecode("0033568ef7b2633c9696766cfa"),
  153. },
  154. {
  155. AESKey: aesKey13to24,
  156. CipherText: mustHexDecode("aa6cfa36cae86b40b1d23a2220ddc0ac900d9aa03c61fcf4a559a4417767089708a776796edb723506"),
  157. ClearHeaderOctets: 8,
  158. Data: mustHexDecode("aa6cfa36cae86b40b916e0eacc1c00d7dcec68ec0b3bbb1a02de8a2d1aa346132e"),
  159. M: 8,
  160. Nonce: mustHexDecode("00103fe41336713c9696766cfa"),
  161. },
  162. {
  163. AESKey: aesKey13to24,
  164. CipherText: mustHexDecode("d0d0735c531e1becf049c24414d253c3967b70609b7cbb7c499160283245269a6f49975bcadeaf"),
  165. ClearHeaderOctets: 12,
  166. Data: mustHexDecode("d0d0735c531e1becf049c24412daac5630efa5396f770ce1a66b21f7b2101c"),
  167. M: 8,
  168. Nonce: mustHexDecode("00764c63b8058e3c9696766cfa"),
  169. },
  170. {
  171. AESKey: aesKey13to24,
  172. CipherText: mustHexDecode("77b60f011c03e1525899bcae5545ff1a085ee2efbf52b2e04bee1e2336c73e3f762c0c7744fe7e3c"),
  173. ClearHeaderOctets: 12,
  174. Data: mustHexDecode("77b60f011c03e1525899bcaee88b6a46c78d63e52eb8c546efb5de6f75e9cc0d"),
  175. M: 8,
  176. Nonce: mustHexDecode("00f8b678094e3b3c9696766cfa"),
  177. },
  178. {
  179. AESKey: aesKey13to24,
  180. CipherText: mustHexDecode("cd9044d2b71fdb8120ea60c0009769ecabdf48625594c59251e6035722675e04c847099e5ae0704551"),
  181. ClearHeaderOctets: 12,
  182. Data: mustHexDecode("cd9044d2b71fdb8120ea60c06435acbafb11a82e2f071d7ca4a5ebd93a803ba87f"),
  183. M: 8,
  184. Nonce: mustHexDecode("00d560912d3f703c9696766cfa"),
  185. },
  186. {
  187. AESKey: aesKey13to24,
  188. CipherText: mustHexDecode("d85bc7e69f944fb8bc218daa947427b6db386a99ac1aef23ade0b52939cb6a637cf9bec2408897c6ba"),
  189. ClearHeaderOctets: 8,
  190. Data: mustHexDecode("d85bc7e69f944fb88a19b950bcf71a018e5e6701c91787659809d67dbedd18"),
  191. M: 10,
  192. Nonce: mustHexDecode("0042fff8f1951c3c9696766cfa"),
  193. },
  194. {
  195. AESKey: aesKey13to24,
  196. CipherText: mustHexDecode("74a0ebc9069f5b375810e6fd25874022e80361a478e3e9cf484ab04f447efff6f0a477cc2fc9bf548944"),
  197. ClearHeaderOctets: 8,
  198. Data: mustHexDecode("74a0ebc9069f5b371761433c37c5a35fc1f39f406302eb907c6163be38c98437"),
  199. M: 10,
  200. Nonce: mustHexDecode("00920f40e56cdc3c9696766cfa"),
  201. },
  202. {
  203. AESKey: aesKey13to24,
  204. CipherText: mustHexDecode("44a3aa3aae6475caf2beed7bc5098e83feb5b31608f8e29c38819a89c8e776f1544d4151a4ed3a8b87b9ce"),
  205. ClearHeaderOctets: 8,
  206. Data: mustHexDecode("44a3aa3aae6475caa434a8e58500c6e41530538862d686ea9e81301b5ae4226bfa"),
  207. M: 10,
  208. Nonce: mustHexDecode("0027ca0c7120bc3c9696766cfa"),
  209. },
  210. {
  211. AESKey: aesKey13to24,
  212. CipherText: mustHexDecode("ec46bb63b02520c33c49fd7031d750a09da3ed7fddd49a2032aabf17ec8ebf7d22c8088c666be5c197"),
  213. ClearHeaderOctets: 12,
  214. Data: mustHexDecode("ec46bb63b02520c33c49fd70b96b49e21d621741632875db7f6c9243d2d7c2"),
  215. M: 10,
  216. Nonce: mustHexDecode("005b8ccbcd9af83c9696766cfa"),
  217. },
  218. {
  219. AESKey: aesKey13to24,
  220. CipherText: mustHexDecode("47a65ac78b3d594227e85e71e882f1dbd38ce3eda7c23f04dd65071eb41342acdf7e00dccec7ae52987d"),
  221. ClearHeaderOctets: 12,
  222. Data: mustHexDecode("47a65ac78b3d594227e85e71e2fcfbb880442c731bf95167c8ffd7895e337076"),
  223. M: 10,
  224. Nonce: mustHexDecode("003ebe94044b9a3c9696766cfa"),
  225. },
  226. {
  227. AESKey: aesKey13to24,
  228. CipherText: mustHexDecode("6e37a6ef546d955d34ab6059f32905b88a641b04b9c9ffb58cc390900f3da12ab16dce9e82efa16da62059"),
  229. ClearHeaderOctets: 12,
  230. Data: mustHexDecode("6e37a6ef546d955d34ab6059abf21c0b02feb88f856df4a37381bce3cc128517d4"),
  231. M: 10,
  232. Nonce: mustHexDecode("008d493b30ae8b3c9696766cfa"),
  233. },
  234. }
  235. if len(cases) != 24 {
  236. t.Fatalf("Expected %d test cases, got: %d", 24, len(cases)) //nolint:revive
  237. t.FailNow() //nolint:revive
  238. }
  239. for idx, c := range cases {
  240. c := c
  241. t.Run(fmt.Sprintf("packet vector #%d", idx+1), func(t *testing.T) {
  242. blk, err := aes.NewCipher(c.AESKey)
  243. if err != nil {
  244. t.Fatalf("could not initialize AES block cipher from key: %v", err)
  245. }
  246. lccm, err := NewCCM(blk, c.M, len(c.Nonce))
  247. if err != nil {
  248. t.Fatalf("could not create CCM: %v", err)
  249. }
  250. t.Run("seal", func(t *testing.T) {
  251. var dst []byte
  252. dst = lccm.Seal(dst, c.Nonce, c.Data[c.ClearHeaderOctets:], c.Data[:c.ClearHeaderOctets])
  253. if !bytes.Equal(c.CipherText[c.ClearHeaderOctets:], dst) {
  254. t.Fatalf("ciphertext does not match, wanted %v, got %v",
  255. c.CipherText[c.ClearHeaderOctets:], dst)
  256. }
  257. })
  258. t.Run("open", func(t *testing.T) {
  259. var dst []byte
  260. dst, err = lccm.Open(dst, c.Nonce, c.CipherText[c.ClearHeaderOctets:], c.CipherText[:c.ClearHeaderOctets])
  261. if err != nil {
  262. t.Fatalf("failed to unseal: %v", err)
  263. }
  264. if !bytes.Equal(c.Data[c.ClearHeaderOctets:], dst) {
  265. t.Fatalf("plaintext does not match, wanted %v, got %v",
  266. c.Data[c.ClearHeaderOctets:], dst)
  267. }
  268. })
  269. })
  270. }
  271. }
  272. func TestNewCCMError(t *testing.T) {
  273. cases := map[string]struct {
  274. vector
  275. err error
  276. }{
  277. "ShortNonceLength": {
  278. vector{
  279. AESKey: aesKey1to12,
  280. M: 8,
  281. Nonce: mustHexDecode("a0a1a2a3a4a5"),
  282. }, errInvalidNonceSize,
  283. },
  284. "LongNonceLength": {
  285. vector{
  286. AESKey: aesKey1to12,
  287. M: 8,
  288. Nonce: mustHexDecode("0001020304050607080910111213"),
  289. }, errInvalidNonceSize,
  290. },
  291. "ShortTag": {
  292. vector{
  293. AESKey: aesKey1to12,
  294. M: 3,
  295. Nonce: mustHexDecode("00010203040506070809101112"),
  296. }, errInvalidTagSize,
  297. },
  298. "LongTag": {
  299. vector{
  300. AESKey: aesKey1to12,
  301. M: 17,
  302. Nonce: mustHexDecode("00010203040506070809101112"),
  303. }, errInvalidTagSize,
  304. },
  305. }
  306. for name, c := range cases {
  307. c := c
  308. t.Run(name, func(t *testing.T) {
  309. blk, err := aes.NewCipher(c.AESKey)
  310. if err != nil {
  311. t.Fatalf("could not initialize AES block cipher from key: %v", err)
  312. }
  313. if _, err := NewCCM(blk, c.M, len(c.Nonce)); !errors.Is(err, c.err) {
  314. t.Fatalf("expected error '%v', got '%v'", c.err, err)
  315. }
  316. })
  317. }
  318. }
  319. func TestSealError(t *testing.T) {
  320. cases := map[string]struct {
  321. vector
  322. err error
  323. }{
  324. "InvalidNonceLength": {
  325. vector{
  326. Data: mustHexDecode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e"),
  327. M: 8,
  328. Nonce: mustHexDecode("00000003020100a0a1a2a3a4"), // short
  329. }, errInvalidNonceSize,
  330. },
  331. "PlaintextTooLong": {
  332. vector{
  333. Data: make([]byte, 100000),
  334. M: 8,
  335. Nonce: mustHexDecode("00000003020100a0a1a2a3a4a5"),
  336. }, errPlaintextTooLong,
  337. },
  338. }
  339. blk, err := aes.NewCipher(aesKey1to12)
  340. if err != nil {
  341. t.Fatalf("could not initialize AES block cipher from key: %v", err)
  342. }
  343. lccm, err := NewCCM(blk, 8, 13)
  344. if err != nil {
  345. t.Fatalf("could not create CCM: %v", err)
  346. }
  347. for name, c := range cases {
  348. c := c
  349. t.Run(name, func(t *testing.T) {
  350. defer func() {
  351. err, ok := recover().(error)
  352. if !ok {
  353. t.Errorf("expected panic '%v', got '%v'", c.err, err)
  354. }
  355. if !errors.Is(err, c.err) {
  356. t.Errorf("expected panic '%v', got '%v'", c.err, err)
  357. }
  358. }()
  359. var dst []byte
  360. _ = lccm.Seal(dst, c.Nonce, c.Data[c.ClearHeaderOctets:], c.Data[:c.ClearHeaderOctets])
  361. })
  362. }
  363. }
  364. func TestOpenError(t *testing.T) {
  365. cases := map[string]struct {
  366. vector
  367. err error
  368. }{
  369. "CiphertextTooShort": {
  370. vector{
  371. CipherText: make([]byte, 10),
  372. ClearHeaderOctets: 8,
  373. Nonce: mustHexDecode("00000003020100a0a1a2a3a4a5"),
  374. }, errCiphertextTooShort,
  375. },
  376. "CiphertextTooLong": {
  377. vector{
  378. CipherText: make([]byte, 100000),
  379. ClearHeaderOctets: 8,
  380. Nonce: mustHexDecode("00000003020100a0a1a2a3a4a5"),
  381. }, errCiphertextTooLong,
  382. },
  383. }
  384. blk, err := aes.NewCipher(aesKey1to12)
  385. if err != nil {
  386. t.Fatalf("could not initialize AES block cipher from key: %v", err)
  387. }
  388. lccm, err := NewCCM(blk, 8, 13)
  389. if err != nil {
  390. t.Fatalf("could not create CCM: %v", err)
  391. }
  392. for name, c := range cases {
  393. c := c
  394. t.Run(name, func(t *testing.T) {
  395. var dst []byte
  396. _, err = lccm.Open(dst, c.Nonce, c.CipherText[c.ClearHeaderOctets:], c.CipherText[:c.ClearHeaderOctets])
  397. if !errors.Is(err, c.err) {
  398. t.Errorf("expected error '%v', got '%v'", c.err, err)
  399. }
  400. })
  401. }
  402. }