LynXS_

Untitled

Jan 17th, 2026 (edited)
123
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.27 KB | None | 0 0
  1. local ffi = require("@lune/ffi")
  2.  
  3. -- load Windows crypto provider
  4. local bcrypt = ffi.open("bcrypt.dll")
  5.  
  6. -- define function signatures (Lune style)
  7. local BCryptOpenAlgorithmProvider = bcrypt:func(
  8. "BCryptOpenAlgorithmProvider",
  9. { "pointer", "pointer", "pointer", "u32" },
  10. "i32"
  11. )
  12.  
  13. local BCryptSetProperty = bcrypt:func(
  14. "BCryptSetProperty",
  15. { "pointer", "pointer", "pointer", "u32", "u32" },
  16. "i32"
  17. )
  18.  
  19. local BCryptGenerateSymmetricKey = bcrypt:func(
  20. "BCryptGenerateSymmetricKey",
  21. { "pointer", "pointer", "pointer", "u32", "pointer", "u32", "u32" },
  22. "i32"
  23. )
  24.  
  25. local BCryptEncrypt = bcrypt:func(
  26. "BCryptEncrypt",
  27. { "pointer", "pointer", "u32", "pointer", "pointer", "u32", "pointer", "u32", "pointer", "u32" },
  28. "i32"
  29. )
  30.  
  31. local BCryptDecrypt = bcrypt:func(
  32. "BCryptDecrypt",
  33. { "pointer", "pointer", "u32", "pointer", "pointer", "u32", "pointer", "u32", "pointer", "u32" },
  34. "i32"
  35. )
  36.  
  37. local BCryptDestroyKey = bcrypt:func(
  38. "BCryptDestroyKey",
  39. { "pointer" },
  40. "i32"
  41. )
  42.  
  43. local BCryptCloseAlgorithmProvider = bcrypt:func(
  44. "BCryptCloseAlgorithmProvider",
  45. { "pointer", "u32" },
  46. "i32"
  47. )
  48.  
  49. -- constants
  50. local AES = "AES"
  51. local CBC = "ChainingModeCBC"
  52.  
  53. -- PKCS7 padding
  54. local function pad(data)
  55. local pad = 16 - (#data % 16)
  56. return data .. string.rep(string.char(pad), pad)
  57. end
  58.  
  59. local function unpad(data)
  60. local n = string.byte(data, -1)
  61. return data:sub(1, -1 - n)
  62. end
  63.  
  64. -- AES CBC encrypt
  65. local function aes_encrypt(key: string, iv: string, plaintext: string): string
  66. assert(#key == 16 or #key == 32, "key must be 16 or 32 bytes")
  67. assert(#iv == 16, "iv must be 16 bytes")
  68.  
  69. local arena = ffi.arena()
  70.  
  71. local alg = arena:alloc(ffi.sizeof("pointer"))
  72. local keyh = arena:alloc(ffi.sizeof("pointer"))
  73.  
  74. local keybuf = arena:alloc(#key)
  75. ffi.copy(keybuf, key, #key)
  76.  
  77. local ivbuf = arena:alloc(#iv)
  78. ffi.copy(ivbuf, iv, #iv)
  79.  
  80. local data = pad(plaintext)
  81. local inbuf = arena:alloc(#data)
  82. ffi.copy(inbuf, data, #data)
  83.  
  84. -- open AES provider
  85. assert(BCryptOpenAlgorithmProvider(alg, AES, nil, 0) == 0)
  86.  
  87. -- set CBC mode
  88. assert(BCryptSetProperty(ffi.readpointer(alg), CBC, CBC, #CBC, 0) == 0)
  89.  
  90. -- create key
  91. assert(BCryptGenerateSymmetricKey(
  92. ffi.readpointer(alg),
  93. keyh,
  94. nil,
  95. 0,
  96. keybuf,
  97. #key,
  98. 0
  99. ) == 0)
  100.  
  101. -- query output size
  102. local outlenbuf = arena:alloc(4)
  103. BCryptEncrypt(
  104. ffi.readpointer(keyh),
  105. inbuf,
  106. #data,
  107. nil,
  108. ivbuf,
  109. #iv,
  110. nil,
  111. 0,
  112. outlenbuf,
  113. 0
  114. )
  115.  
  116. local outlen = ffi.readu32(outlenbuf)
  117. local outbuf = arena:alloc(outlen)
  118.  
  119. -- encrypt
  120. assert(BCryptEncrypt(
  121. ffi.readpointer(keyh),
  122. inbuf,
  123. #data,
  124. nil,
  125. ivbuf,
  126. #iv,
  127. outbuf,
  128. outlen,
  129. outlenbuf,
  130. 0
  131. ) == 0)
  132.  
  133. BCryptDestroyKey(ffi.readpointer(keyh))
  134. BCryptCloseAlgorithmProvider(ffi.readpointer(alg), 0)
  135.  
  136. return ffi.string(outbuf, outlen)
  137. end
  138.  
  139. -- AES CBC decrypt
  140. local function aes_decrypt(key: string, iv: string, cipher: string): string
  141. assert(#key == 16 or #key == 32)
  142. assert(#iv == 16)
  143.  
  144. local arena = ffi.arena()
  145.  
  146. local alg = arena:alloc(ffi.sizeof("pointer"))
  147. local keyh = arena:alloc(ffi.sizeof("pointer"))
  148.  
  149. local keybuf = arena:alloc(#key)
  150. ffi.copy(keybuf, key, #key)
  151.  
  152. local ivbuf = arena:alloc(#iv)
  153. ffi.copy(ivbuf, iv, #iv)
  154.  
  155. local inbuf = arena:alloc(#cipher)
  156. ffi.copy(inbuf, cipher, #cipher)
  157.  
  158. assert(BCryptOpenAlgorithmProvider(alg, AES, nil, 0) == 0)
  159. assert(BCryptSetProperty(ffi.readpointer(alg), CBC, CBC, #CBC, 0) == 0)
  160.  
  161. assert(BCryptGenerateSymmetricKey(
  162. ffi.readpointer(alg),
  163. keyh,
  164. nil,
  165. 0,
  166. keybuf,
  167. #key,
  168. 0
  169. ) == 0)
  170.  
  171. local outlenbuf = arena:alloc(4)
  172. BCryptDecrypt(
  173. ffi.readpointer(keyh),
  174. inbuf,
  175. #cipher,
  176. nil,
  177. ivbuf,
  178. #iv,
  179. nil,
  180. 0,
  181. outlenbuf,
  182. 0
  183. )
  184.  
  185. local outlen = ffi.readu32(outlenbuf)
  186. local outbuf = arena:alloc(outlen)
  187.  
  188. assert(BCryptDecrypt(
  189. ffi.readpointer(keyh),
  190. inbuf,
  191. #cipher,
  192. nil,
  193. ivbuf,
  194. #iv,
  195. outbuf,
  196. outlen,
  197. outlenbuf,
  198. 0
  199. ) == 0)
  200.  
  201. BCryptDestroyKey(ffi.readpointer(keyh))
  202. BCryptCloseAlgorithmProvider(ffi.readpointer(alg), 0)
  203.  
  204. return unpad(ffi.string(outbuf, outlen))
  205. end
  206.  
  207. -- test
  208. local key = "1234567890123456"
  209. local iv = "abcdefghijklmnop"
  210.  
  211. local enc = aes_encrypt(key, iv, "hello lune")
  212. local dec = aes_decrypt(key, iv, enc)
  213.  
  214. print(enc)
  215. print(dec)
Advertisement
Add Comment
Please, Sign In to add comment