help-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Let us see how to encrypt with Emacs?


From: Jean Louis
Subject: Re: Let us see how to encrypt with Emacs?
Date: Fri, 9 Jul 2021 15:27:29 +0300
User-agent: Mutt/2.0.7+183 (3d24855) (2021-05-28)

I am thinking to have it simpler for practical purposes, so here
is what I made now:

(defun pad-to-multiple-bytes (string max)
  "Return string padded to multiple of MAX bytes."
  (let* ((bytes (string-bytes string))
         (multiple (truncate (/ bytes max)))
         (multiple (if (zerop multiple) max (* (1+ multiple) max))))
    (string-pad string multiple)))

(defun rcd-encrypt-chacha20-64 (string password)
  "Encrypt STRING with PASSWORD by using CHACHA20-64 cipher."
  (let* ((key (pad-to-multiple-bytes password 32))
         (iv (substring (gnutls-hash-digest "SHA512" password) 0 15))
         (iv (pad-to-multiple-bytes iv 16))
         (string (pad-to-multiple-bytes string 64)))
    (car (gnutls-symmetric-encrypt "CHACHA20-64" key iv string))))

(rcd-encrypt-chacha20-64 "Some text here" "123Mypassword123") ⇒ 
"\352\200\333\2460\246\330\211P\311\207\260m\211RD0\222\237\200K=\216\214\267\320p\273>,T\262
 k\361\336;i\336I\325Xi\200G\325\303\312\320\254Dg9"

(defun rcd-decrypt-chacha20-64 (encrypted-string password)
  "Decrypt ENCRYPTED-STRING with PASSWORD by using CHACHA20-64 cipher.

The return string will be trimmed."
  (let* ((key (pad-to-multiple-bytes password 32))
         (iv (substring (gnutls-hash-digest "SHA512" password) 0 15))
         (iv (pad-to-multiple-bytes iv 16))
         (decrypted (gnutls-symmetric-decrypt "CHACHA20-64" key iv 
encrypted-string))
         (decrypted (string-trim (car decrypted))))
    decrypted))

(rcd-decrypt-chacha20-64 (rcd-encrypt-chacha20-64 "Some text here" 
"123Mypassword123") "123Mypassword123") ⇒ "Some text here"

As that is more practical function.

And maybe making a more generic function would be helpful. 

For generci function I wonder if the function `gnutls-cipers'
really yields alist or not, I am not sure, but this below seem to
work:

(alist-get 'RC2-40 (gnutls-ciphers)) ⇒ (:cipher-id 17 :type 
gnutls-symmetric-cipher :cipher-aead-capable nil :cipher-tagsize 0 
:cipher-blocksize 8 :cipher-keysize 5 :cipher-ivsize 8)

Then result yields basically plist:

(plist-get (alist-get 'RC2-40 (gnutls-ciphers)) :cipher-id) ⇒ 17

Then I have the generic function that will satisfy my needs:

(defun rcd-encrypt-decrypt (enc-dec password &optional decrypt cipher digest)
  "Encrypt or decrypt ENC-DEC wi PASSWORD.

Default cipher is CHACHA20-64 or CIPHER as defined by the
function `gnutls-ciphers'. 

Default digest is SHA512 or HASH as defined by the function
`gnutls-digests'.

Function encrypts by default, with DECRYPT being anything but
NIL, it will decrypt the ENC-DEC. "
  (let* ((cipher (or cipher "CHACHA20-64"))
         (cipher-plist (alist-get cipher (gnutls-ciphers) nil nil 'string=))
         (cipher-key-size (plist-get cipher-plist :cipher-keysize))
         (key (pad-to-multiple-bytes password cipher-key-size))
         (digest (or digest "SHA512"))
         (hash (gnutls-hash-digest digest password))
         (iv-size (plist-get cipher-plist :cipher-ivsize))
         (iv (substring hash 0 iv-size))
         (iv (string-pad iv iv-size))
         (block-size (plist-get cipher-plist :cipher-blocksize))
         (enc-dec (if decrypt enc-dec (pad-to-multiple-bytes enc-dec 
block-size))))
    (if decrypt
        (string-trim (car (gnutls-symmetric-decrypt cipher key iv enc-dec)))
      (car (gnutls-symmetric-encrypt cipher key iv enc-dec)))))

(rcd-encrypt-decrypt "My string here" "My password 123") ⇒ 
"\273/\322Xk_m@\372a\323\257\317\330\301\263\224\220\351\303>\241\245[\344\226\203;

-\244\265\331\263\253\354\230\206\3140\221\341\370\361&\333\317\357T?(\302#\206&\355~\200"

(rcd-encrypt-decrypt (rcd-encrypt-decrypt "My string here" "My password 123") 
"My password 123" t) ⇒ "My string here"

Now I come to what I really need, that is to encrypt and encode by base64 
method:

(defun rcd-encrypt-decrypt-base64 (enc-dec password &optional decrypt cipher 
digest no-line-break)
  "Use base64 encoding and decoding with encryption."
  (let* ((enc-dec (if decrypt (base64-decode-string enc-dec) enc-dec))
         (enc-dec (rcd-encrypt-decrypt enc-dec password decrypt cipher digest))
         (enc-dec (if decrypt enc-dec (base64-encode-string enc-dec 
no-line-break))))
    enc-dec))

(rcd-encrypt-decrypt-base64 "My string" "MyPassword987" nil nil nil t) ⇒ 
"XOxgVUXurXzqWP9y5pzs6IwjWafdG6sWcqVz13HzfYhnWLiDn3/yo8DuMnrTuIjCC9BEyAxqW7dmAt9h0bwKoA=="

(rcd-encrypt-decrypt-base64 
"XOxgVUXurXzqWP9y5pzs6IwjWafdG6sWcqVz13HzfYhnWLiDn3/yo8DuMnrTuIjCC9BEyAxqW7dmAt9h0bwKoA=="
 "MyPassword987" t) ⇒ "My string"

As that I can pass to the URL for Double Opt-In purposes instead
revealing the information to the public. Then I can even put
whole Emacs hash into the URL:

(setq hash (make-hash-table))
(puthash "MID" 123 hash)
(puthash "EID" 98 hash)
(puthash "CID" 333 hash)
(puthash "redirect" "https://www.example.com"; hash)

hash ⇒ #s(hash-table size 65 test eql rehash-size 1.5 rehash-threshold 0.8125 
data ("MID" 123 "CID" 333 "EID" 98 "redirect" "https://www.example.com";))

(rcd-encrypt-decrypt-base64 (prin1-to-string hash) "MyPassword987" nil nil nil 
t) ⇒ 
"MuZoTlDvrD/5Gb0+o5y/odZmWbHIG/9TIfFzkiC/fdoiEPnQ13Kh6pqrMmvdrYiQTpgFm0RnD/80R4wpnvBOoKGtDWQnpv/5191ZzmNRmNDBDLJdG/f/Iv9VR0LmieP38cvWtZ3uxGWZdsaWCBhtsqDDYFrTS6mrPXmmyGE4hjedt3Z9E9cDOStlgiS+ynwwmlhNJf0Jga5848y/I+To2+zp3qw9Z+KiOhq+Vr2Mpm8/6zFQ9YxuDZNy9LWjJL/L"

And use that to subscribe users, unsubscribe and similar with
more safety that users will not abuse my system.


Jean

Take action in Free Software Foundation campaigns:
https://www.fsf.org/campaigns

In support of Richard M. Stallman
https://stallmansupport.org/



reply via email to

[Prev in Thread] Current Thread [Next in Thread]