1
0

crypto.lisp 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  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. (when (find #\: data)
  20. (error "Bad data."))
  21. (let* ((message (format nil "~A:~A:~A:~A"
  22. chat-id
  23. (base64:integer-to-base64-string
  24. (+ ttl (local-time:timestamp-to-universal (local-time:now))))
  25. section data))
  26. (encoded (format nil "~A$~A" message (token-hmac message hmac-length))))
  27. (when (> (length encoded) +telegram-max-callback-data-length+)
  28. (error "Max callback length exceeded"))
  29. encoded))
  30. (defun decode-callback-data (chat-id raw-data &optional (hmac-length 12))
  31. (destructuring-bind (message hmac)
  32. (split-sequence:split-sequence #\$ raw-data :from-end t :count 2)
  33. (destructuring-bind (cid expire section data)
  34. (split-sequence:split-sequence #\: message :count 4)
  35. (unless (= chat-id (parse-integer cid))
  36. (error "Wrong chat id."))
  37. (unless (>= (base64:base64-string-to-integer expire)
  38. (local-time:timestamp-to-universal (local-time:now)))
  39. (error "Expired."))
  40. (unless (equal hmac (token-hmac message hmac-length))
  41. (error "Bad data."))
  42. (values data (intern (string-upcase section) "KEYWORD")))))
  43. (defun encode-oauth-state (section state)
  44. (format nil "~A$~A" section state))
  45. (defun decode-oauth-state (raw-state)
  46. (destructuring-bind (section data)
  47. (split-sequence:split-sequence #\$ raw-state :count 2)
  48. (values data (intern (string-upcase section) "KEYWORD"))))