1
0

crypto.lisp 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. (in-package :cl-user)
  2. (defpackage chatikbot.crypto
  3. (:use :cl)
  4. (:import-from :chatikbot.telegram
  5. :*telegram-token*
  6. :+telegram-max-callback-data-length+)
  7. (:export :token-hmac
  8. :encode-callback-data
  9. :decode-callback-data
  10. :encode-oauth-state
  11. :decode-oauth-state))
  12. (in-package #:chatikbot.crypto)
  13. (defun token-hmac (message &optional (hmac-length 12))
  14. (let ((hmac (crypto:make-hmac (crypto:ascii-string-to-byte-array *telegram-token*) :sha256)))
  15. (crypto:update-hmac hmac (crypto:ascii-string-to-byte-array message))
  16. (base64:usb8-array-to-base64-string
  17. (subseq (crypto:hmac-digest hmac) 0 hmac-length) :uri t)))
  18. (defun encode-callback-data (chat-id section data &optional (ttl 600) (hmac-length 12))
  19. (unless (stringp data)
  20. (setf data (format nil "~A" data)))
  21. (when (find #\: data)
  22. (error "Bad data."))
  23. (let* ((message (format nil "~A:~A:~A:~A"
  24. chat-id
  25. (base64:integer-to-base64-string
  26. (+ ttl (local-time:timestamp-to-universal (local-time:now))))
  27. section data))
  28. (encoded (format nil "~A$~A" message (token-hmac message hmac-length))))
  29. (when (> (length encoded) +telegram-max-callback-data-length+)
  30. (error "Max callback length exceeded"))
  31. encoded))
  32. (defun decode-callback-data (chat-id raw-data &optional (hmac-length 12))
  33. (destructuring-bind (message hmac)
  34. (split-sequence:split-sequence #\$ raw-data :from-end t :count 2)
  35. (destructuring-bind (cid expire section data)
  36. (split-sequence:split-sequence #\: message :count 4)
  37. (unless (= chat-id (parse-integer cid))
  38. (error "Wrong chat id."))
  39. (unless (>= (base64:base64-string-to-integer expire)
  40. (local-time:timestamp-to-universal (local-time:now)))
  41. (error "Expired."))
  42. (unless (equal hmac (token-hmac message hmac-length))
  43. (error "Bad data."))
  44. (values data (intern (string-upcase section) "KEYWORD")))))
  45. (defun encode-oauth-state (section state)
  46. (format nil "~A$~A" section state))
  47. (defun decode-oauth-state (raw-state)
  48. (destructuring-bind (section data)
  49. (split-sequence:split-sequence #\$ raw-state :count 2)
  50. (values data (intern (string-upcase section) "KEYWORD"))))