triptico.com

Un naufragio personal

Documents

Storing multiple sensible documents in public services

Use case

You have a rather large set of files that you want to backup into any public storage service (like Dropbox, Microsoft OneDrive, Google Drive or similar) but you don't want them to be able to see what's in them. Many of these services say that they don't take a look of what you store in their servers. Obviously, this is a lie. Also, these sites don't mind a fuck on security and users credentials leak every now and then, so your files can end on some script kiddy hard drive and you don't want these motherfuckers to have access to your data.

Let's suppose you have a folder named world-domination-plan full of JPGs of public institution blueprints, HOWTOs for home-made virus strains and the data sheets and architecture docs for your army of robots, summing up to 5GB of data or so. Let's also suppose you use Linux, what you should for many reasons.

PGP / GNUPG (assymmetric)

The easiest way is to use a personal private/public key system like GPG to make a package of your data and encrypt it:

 tar cvf - world-domination-plan/ | gpg -r bigbad@example.com -e > plan.tar.gpg

This is very convenient, as no passwords are requested and can be executed as a non-interactive process from an unattended, time triggered service like cron. Of course, you must have the public key for bigbad@example.com in your keyring. Once done (this is relative fast), you can upload plan.tar.gpg to any of the crappy services mentioned above and only users having the private key for bigbad@example.com can extract the package contents. Please take note that you don't need the private key in the system where you create this package (so you don't need to be the big bad, only a mook).

Extracting the package is done with the reverse process:

 gpg -d plan.tar.gpg | tar xvf -

In this case, the password for the private key related to bigbad@example.com is requested, so it's an interactive process. Of course, you need that private key in you keyring.

PGP / GNUPG (symmetric)

Sometimes, the need of having a correctly configured GPG system with the necessary private key is not convenient or possible (like, say, you must decrypt the package in a computer that is not your own). For this case it's easier to use classical, symmetric encryption key when encrypting the data.

This is done by typing

 tar cvf - world-domination-plan/ | gpg --symmetric > plan.tar.gpg

This time a passphrase will be requested twice and, if both match, used for encrypting the package. Obviously you will need the same password in the decryption process (which is, happily, exactly the same as in the previous case):

 gpg -d plan.tar.gpg | tar xvf -

The passphrase used in the encryption step will be requested.

Loopback, encrypted filesystems

This is fine, but it has some drawbacks: on one hand, you have the world-domination-plan folder always there in the clear, not only when you are using them (unless you do the cumbersome dance of decrypting / using / encrypting back / deleting the folder everytime you confabulate); on the other hand, while in the backup process, you have all the data twice, and that can be a problem if the size of the files is big. Not forgetting that, in this big dataset case, the encryption process can be long.

The solution to all these is to use a regular file, but one that contains a real filesystem — as if it was an external drive — that you can mount and unmount at will. Of course, this filesystem-in-a-file will also be encrypted, so the benefits above still apply.

First you have to create a file with a size that will be enough to store your current and foreseeable data (think about this size wisely; it's not easy to resize it if you fill it). Let's say it's 6GB. Create it this way:

 dd if=/dev/zero of=plan.img bs=1M count=6000 status=progress

This will create a file named plan.img (full of zeros) with 6000 blocks of 1M of size. It may take a while.

Now, using the cryptsetup tool, you must format this file as a luks encrypted volume:

 sudo cryptsetup -y -v luksFormat plan.img

This will ask for your password (for sudo, as this is a privileged operation), an explicit confirmation (this is a destructive operation on the possible contents of plan.img) and twice the passphrase that will be used for encryption.

The following step is 'opening' the encrypted volume (take note that it's still unable to store anything):

 sudo cryptsetup open plan.img the-plan

This will map plan.img to a new block file named /dev/mapper/the-plan. The passphrase used in the formatting process shall be requested.

Now you can create a filesystem inside this new block device:

 sudo mkfs -t ext4 /dev/mapper/the-plan

It's ready. Close everything:

 sync && sync && sync && sudo cryptsetup close the-plan

Please take note that you only have to perform this fuckton of cumbersome steps once.

The usage is similar. To mount the storage in a temporary directory:

 mkdir -p world-domination-plan-tmp
 sudo cryptsetup open plan.img the-plan
 sudo mount /dev/mapper/the-plan world-domination-plan-tmp

The world-domination-plan-tmp is where you must store all your work. The root folder in this loopbacked filesystem is by default owned by root; you most probably want to change its ownership to you (only necessary once).

After working, do the reverse:

 sync && sync && sync
 sudo umount world-domination-plan-tmp
 sudo cryptsetup close the-plan
 rmdir -p world-domination-plan-tmp

You may be an evil genius, but may also be an old fart like me that cannot remember all this magical crap, so you'll automate it by creating beautiful scripts.

Now you have your portable plan.img that you can backup everywhere you want. An interesting feature is that, being a file system, the total content of the file don't change much after each usage, so it can be copied efficiently through the network by intelligent syncing tools like rsync. The GPG'ed tar files in the first examples are completely different on each session so they do not benefit of syncing copy programs.

Other remote storage ideas

If the file has a reasonable size, you can have cheap storage by emailing it to yourself to a Gmail account or similar. Or, even better, by storing it as an attachment of a Draft message in one of these webmail accounts. I've heard some primitive boogeymen communicated this way: through draft messages in a webmail account with credentials known by all of them (data do not leave the servers, so it's more difficult for James Bond's sweatshop spy network to eavesdrop them).

End notes

Dexter uses all these encryption techniques for his own world domination plan, so he can dream of new ways of inflicting pain from his warm lair without worrying about enemy agents and other fuckers.


Meet the new boss.

Remember that you don't need to be a world dominating son of a bitch to require privacy; many people will insist that you only need it if you have something to hide. Don't trust them.


Ángel Ortega <angel@triptico.com>

GPG Cheat Sheet

This is a very basic guide to use GPG (GNU Privacy Guard), the free software version of the classic PGP (Pretty Good Privacy) tool for signing, encrypting and verifying information. It can be handy if your Email client does not directly support it. This guide explicitly do not explain creating and maintaining keys and keyrings.

For this tutorial we have the following two individuals: Angel, with email address angel@triptico.com and Johannes, with email address johannes@comam.es. They both have GPG installed on their systems and have valid keys. Additionally, each user have another one's public key installed in ther keyrings.

Also, there is a two line message they want to share:

 I am the voice of Mother Earth,
 from whence all horrors have their birth.

Signing

Angel wants to send the creepy message to Johannes. Also, he wants to be sure that Johannes can check that he is who really sent the message. So he runs the following command in its terminal:

 gpg -s --clearsign

GPG politely says the following:

 You need a passphrase to unlock the secret key for
 user: "Angel <angel@triptico.com>"
 1024-bit DSA key, ID 70C9B100, created 2012-11-07
 Enter passphrase:

This operation implies the use of Angel's private key, that is password-protected inside his keyring. If the password is correctly entered, GPG waits silently for text from its standard input. Angel pastes the message and GPG dumps the following:

 -----BEGIN PGP SIGNED MESSAGE-----
 Hash: SHA1
 I am the voice of Mother Earth,
 from whence all horrors have their birth.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 iEYEARECAAYFAlvrxGIACgkQ5CXHVHDJsQBOagCfQAFQoZyFfegGZUa8oWwn/srg
 1RwAoMFcDABbLpqaqpwIVqv5U4pYvdVb
 =q64b
 -----END PGP SIGNATURE-----

This piece of text (including the BEGIN... and END... lines) can be pasted to the email body of a message sent to Johannes. Please note that you can write whatever you want outside the PGP boundaries and the message will still be considered valid when the signature is checked. So this can be the full email body:

 Hey, Johannes. This is what he said:
 -----BEGIN PGP SIGNED MESSAGE-----
 Hash: SHA1
 I am the voice of Mother Earth,
 from whence all horrors have their birth.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 iEYEARECAAYFAlvrxGIACgkQ5CXHVHDJsQBOagCfQAFQoZyFfegGZUa8oWwn/srg
 1RwAoMFcDABbLpqaqpwIVqv5U4pYvdVb
 =q64b
 -----END PGP SIGNATURE-----
 Best regards, Angel

Of course, the surrounding text must not be considered signed text. This is a common mistake.

Checking signatures

Johannes receives the message in his Inbox. He's absolutely unsure if it's really Angel who quoted the eerie text; so, he just calls GPG with no arguments:

 gpg

And gets the following reply:

 gpg: Go ahead and type your message ...

Johannes selects and copies the full message body and pastes it into GPG's standard input. Then the program replies:

 I am the voice of Mother Earth,
 from whence all horrors have their birth.
 gpg: Signature made Tue Nov 13 15:02:38 2018 CET using DSA key ID 70C9B100
 gpg: Good signature from "Angel <angel@triptico.com>"

So Johannes can be confident than Angel really sent the two-line message (the rest of the text is considered irrelevant and is ignored). GPG does not need any password to check the signature: all it needs is Angel's public key that it's stored in Johannes' keyring but not protected in any way (Angel's public key can be shown in his web home page or printed and glued on the street lamps of the town if he wants, as it's not sensible information).

Please note that, though GPG apparently mixed the message and its own information, the first one is sent to the standard output stream and the second one to its standard error/status stream; Johannes only sees them together because of the way his terminal shows these channels by default.

Tampering detection

Let's suppose some evil being tries to feed its dirty lies to Johannes, trying to take advantage of the confidence between both and impersonating as Angel. So it somehow obtains a copy of the message and does some subtle changes:

 Hey, Johannes. This is what he said:
 -----BEGIN PGP SIGNED MESSAGE-----
 Hash: SHA1
 I am the voice of Mother Moon,
 from whence all horrors have their doom.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 iEYEARECAAYFAlvrxGIACgkQ5CXHVHDJsQBOagCfQAFQoZyFfegGZUa8oWwn/srg
 1RwAoMFcDABbLpqaqpwIVqv5U4pYvdVb
 =q64b
 -----END PGP SIGNATURE-----
 Best regards, Angel

Johannes repeats the previous operation but gets the following output instead:

 I am the voice of Mother Moon,
 from whence all horrors have their doom.
 gpg: Signature made Tue Nov 13 15:02:38 2018 CET using DSA key ID 70C9B100
 gpg: BAD signature from "Angel <angel@triptico.com>"

That "BAD signature..." thing should trigger all kind of alarms.

The GPG tool also returns different output values for valid and invalid operations that can be useful in scripts and programs. If you are not a programmer nor a sysadmin, you can ignore this.

Encrypting

But Angel may occasionally consider that proving his authorship is not enough; he wants the message to be absolutely hidden to anyone but Johannes. So he opts for PGP/GPG encryption, invoking the command

 gpg -e -a -r johannes@comam.es

and pasting the two-lines message into GPG's standard input. GPG barfs the following wall of text:

 -----BEGIN PGP MESSAGE-----
 Version: GnuPG v1
 hQQOA6n6KzujHJfZEBAAkrlIZp/8IpWhw/H4pjCCzl1GgDvpLiqAvw4b1x9SXcPO
 bH+yp9M8K34+Slp7QIsBWWp+Z49ZAWeendMSW32iMoxakqt4K2PV27S8qgKAqqPk
 bWjCFmJ7ERIy1XSxarSUJaRzvWhwXI/9NVecei6boogSlowxce1GMvranzMJKR3J
 RrMR5AsfHWpnjyvcOjNV+o/OGrE6avPitW4ieWX0PzrLdgXS6tkwFUu9pOeB6OF+
 YRgVQKwtcEoPk92PHBGlvfahvT3KbWaso6OOa7mQHI+YgjbA3g2pCDobcsm30wED
 2Sw2XbU17KQWKU5YUm/RMNhsvYFrYnBA/jiHzqmsw4YeJrImu2MfkjScTgiAdL3S
 hIqGz3+AEBH+lTLHKPF3spQV9GDkn2es6DpRmxVF5TOEsb1toUznAqsADwz0Edlb
 3FEzeN7Kizui8UJ+HR6al+UiDm0X5v03r1tCMjxmZnq4fkmDG5/tH+j1319s33G7
 xDf/upUw1W5XLd+zBgdiTHD1ADxT4fWFiRH6by+CLTdFwt62mREmd1lW6YxwhMEV
 RGGZQzyLp3uVOg1z4jT2q7bz4MOBEPxY1L44zOENkH54yIITQ46Ambiwc572iJQQ
 /vP23oFRDJQdvHndxjlbFA2hJMSRavzTn3VzUYJzPGbnB2JzULUyqOH/obL4TMYP
 /2oxdkJjqQu8Z4xtZOPne5r7q4Ml8mIPtb+h2TbC0hHLi1DDqOQyLJcMmeSKMr3T
 XAOphMzbaHJYBODJB5w86Qxw6wAah1/+j6525NeHYYLPGACb9n8ujnXQP3l/Kpf6
 9/a2+0g3uRCi8GoriLHQN2slEg0hAgSI8t217HTC0fWeNtkVqInd7qUcE04RNa/e
 0nhVXDdbhTRMBkLfSRc/3wELVxrevo0K+bEwPUrJgX/9UROiP0lWJoSE0ezWhdCF
 4XK/K6RQr+WZE6GjpfzTuqDZNjQdphcV2xnTKM5DnauQNOX3+p2T+Ri/8JmnF+xx
 z3MGIxtNWIq1u71ykZZbaNVMRniGQ3QRwJiP7/DN2N08Sz4QO3cjqseK6TeCz+Av
 3vWGP339NUVKS/QHORwmoOQHm9AKwgqQedtgHn/u2hQpLLE35pCZOv5/GgAeJl4d
 /w8Qd7xNKDSVZEN82cYb5LJsY/Z0vVaqII66bm+iZQgdaa+uuNGtVITU3lgRMAJP
 Z0SBbzmNYE/4iLe/B79JK+057KjGlnpswtaYOwe0jS4RB9XRcgE7KBryo4o6h9E9
 udt0WF2h05iHzK7i1ewMJif7WszadnFXG8DifsFiteeEARmetLi89WiSVYdSiFsI
 xRhqIzGA0nz3XWuEBNw00UAl0vtkvDlhGEtSAW19MScc0oAB0TFPswUkicX36SN3
 8kZHiLCmIbucq33h+3TgEtiFjXj+pWFjlz4mTTRAvnr+nYn7FDTgblFMF/NJOXZq
 lSZNeF6PkngjK1+hZTogMBN5OL1iFP1D+IP+7ANydQdQL56V6yaU4YOtJv++l2F4
 ghA5wgMRlC9MNWRzptK2qZJmdQ==
 =NXsq
 -----END PGP MESSAGE-----

Given that GPG has everything it needs to encrypt a message to Johannes (i.e. his public key), no password nor any more information is requested.

Note that, when the message is encrypted, Angel has no way of decrypting it because he does not have Johannes' private key. There is no other way of decrypting this message than using that key.

As with signing, any text can be written surrounding the PGP boundaries. Also, it should not be trusted, as it's not really part of the message.

Decrypting

Johannes receives the block of garbage and proceeds the same as with the signed message:

 gpg

But like every time a private key is involved, GPG asks for the password to the Johannes' keyring:

 You need a passphrase to unlock the secret key for
 user: "Johannes <johannes@comam.es>"
 4096-bit ELG-E key, ID A31C97D9, created 2012-11-07 (main key ID 70C9B100)
Enter passphrase:

If it's entered correctly, GPG waits for text from its standard input. Johannes copies the full message into it and GPG dumps the omen from Mother Earth with some additional information:

 gpg: encrypted with 4096-bit ELG-E key, ID A31C97D9, created 2012-11-07
      "Johannes <johannes@comam.es>"
 I am the voice of Mother Earth,
 from whence all horrors have their birth.

If the encrypted message is garbled someway, GPG will complain about the data block integrity:

 gpg: CRC error; C73B95 - 357B2A

Encrypting and signing

For complete paranoia, a message can be encrypted AND signed. This is how it's done from Angel's view:

 gpg -es -a -r johannes@comam.es

As it needs Angel's private key for signing, the passphrase for his keyring is requested. After pasting the two-line message into GPG's standard input, The response is another scary block of garbage:

 -----BEGIN PGP MESSAGE-----
 Version: GnuPG v1
 hQQOA6n6KzujHJfZEA/8CkbHeZ5Q3VBpsGia90kKJgWcI3/Wbphi5JoSEpm8ezSl
 ffUhxoiO4NKM5hcJM+v+dqq7Wo0C4P2YxVnsUPIf9xk/aF6KmZttFU8H3o5/8+48
 KYQtp2ZBHlSzuDTIwsQyvXAIgg9CyXUTmdALPGaO6X8Yj+UphHghVu6vF1LwQw0k
 G9EfnjRmyEWzb+C4Rzvh6Sf0g+OMvuFtFf9fuSMfzAnwv8+U8diyJYusiuPUrNz7
 Q0b7be5MBhVlTyTfqpnD3zOsqt5EP1NewZgFn9HSxjmHMOGeaR3ahKEQVDyRglqK
 49SsPz402meJf3WrU3HUVsjen5I1q8CrJ+La+uxjodF4JAKhIX1qYJ6hySJI1P+w
 SjGP66VYNFwsYOSkMMlGsehCPNcaNhxZs3UATjd2RsnSNbcs50l+jEQj35EOXApx
 fUaCjUisXfTNz4PPl5slkfkQRTJ1nC8IVboOBk1REFmgJ3KhER+MXhsqqH4gMOH8
 VuGPh4p8nxX5I1WfFGOCtuXCRLCh2kMLdbVG5oDYEr2vPyfaL5EDDIIgao8v+k8E
 mLsWrLOGnSrg14IJ6NZR5zWx9ZC9s9ICPBfIgzKCgqb0wpjLiEP453Ymfl4/MRVr
 L5eXdttOfHHcJIultQcmF4FBlC2pHLXUKyJqkPhnHDnqWCtIwOuZHTS9LY6U5TQP
 /2Moh6TXe+aJTt0k6k4q9/xhCSIWpeOGq24gLQVS5DPTm+tYLSLm6x8nccPmwB2P
 FRXa7BQnDZ4PnOOS1lpo3kapZsmwY5upeZJ6ArI1c8hzHEVrducRPHQC2BrQ9/yj
 cKL7vpQNlHAtaSwI1oYhd+HqQLYUfzpDVxYY3ndk1OEWoNfwLFFcCj4jAMJTwD2J
 JJFhA7nY4CPggkTAr+8xIhzFbkWRexI+g/hfSH0oMKOidMmqCEsfZZStqwM0pfUW
 Ufc28AN+9r6n/6c7qOyZ+HWpbETceLfrUuYwLZ8ExzirJvqILWpMEZduYywDrLko
 8wH73JGHue+bdhW62MNoF45hOaSTBwB7ZZ9LmjqaADPeBVipZUUJPUpTuRg5k+o5
 JfDD6KbbIVl8cqKnLsBRfW5kDov7qKjxZjrbZ88KIa9qk0jrgXc1d0E74Cv/Lvdv
 L7q1Odd1Wsviug0Rdt5YzENXHqZrlCx0BkxBQWdoWhTurdloNITkWir2rxt50tCs
 AJlisig+zGQXkfzoiMMagS4MK2K8slyatT7KpbW9Tr0ueMrHN0Rm1kklw+b7/vnp
 3x8HHJq2Ia8WU3BoaO5cbD8l2d6st/Nhxgf2e+TxBGN87LSpZPzlSOoUISc1pSPB
 RdmACYkrPH+6OaaWjY9uzeSygWbVz3p+lBTL6ZICtQvz0sASAU9lY41R3ZsoTWUv
 /E/fTb4U3y4fTsR4G06Y4gyexh4Yyejh/s2mBc3VG4TCkZyubQilXy8mrhM3NJpj
 DEG6zZQEMtndp1Wq5z+qcvrJ2AF+j5R4nm7zNdt4XjrXOA+3zfzeD+avnfCjKAhT
 Jw0kzUrCzj34xc3iScQmwrdLEETk+66Ypv30ZEcdlzTrQUgcXW1WAqfJfaL8CJf1
 69oTyoWRAAXkpyJGZoIafzS+Cvjupneybqab1+sL8qajpptQBglCaatioFJrZWnk
 qt4LUBgD
 =G+4J
 -----END PGP MESSAGE-----

The difference is that, when Johannes tries to check the message as he usually do:

 gpg

The following is shown:

 You need a passphrase to unlock the secret key for
 user: "Johannes <johannes@comam.es>"
 4096-bit ELG-E key, ID A31C97D9, created 2012-11-07 (main key ID 70C9B100)
Enter passphrase:

This should be expected, as it's a message for Johannes' eyes only. The output is a bit different, though:

 gpg: encrypted with 4096-bit ELG-E key, ID A31C97D9, created 2012-11-07
      "Johannes <johannes@comam.es>"
 I am the voice of Mother Earth,
 from whence all horrors have their birth.
 gpg: Signature made Tue Nov 13 16:03:20 2018 CET using DSA key ID 70C9B100
 gpg: Good signature from "Angel <angel@triptico.com>"

GPG dumps information about the key the message was encrypted for, the message itself and the results of the validation test.

Signing binary files

Sometimes Angel may want to sign a binary file (a zip package, an image, etc.), for the purpose of helping people know that the file he has and the one they have has the same content. But adding PGP/GPG crap to this kind of files cannot be done because it corrupts them; so, you have to use a detached signature. Suppose you have the file

 abraham_lincoln_nude.jpg

Then you can sign it by executing

 gpg -ab abraham_lincoln_nude.jpg

A familiar prompt from GPG will be shown:

 You need a passphrase to unlock the secret key for
 user: "Angel <angel@triptico.com>"
 1024-bit DSA key, ID 70C9B100, created 2012-11-07
Enter passphrase:

After a successful password GPG creates a file with the same name as the signed one, but with the .asc extension appended, and that looks like:

 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 iEYEABECAAYFAlvr2GAACgkQ5CXHVHDJsQCeagCfTn72ZUBeVlWwTMvTMcGIbZsL
 9q4An0ZDXwAaMb5cyHUsybXoXZ/yjw8U
 =R3uI
 -----END PGP SIGNATURE-----

Both the file and the signature can now be made available to others.

Validating signed binary files

Johannes can validate that the binary file and Angel's signature on it match by calling

 gpg abraham_lincoln_nude.jpg.asc

Note that both the file and the signature must be on the same folder. GPG shall return the following:

 gpg: assuming signed data in `abraham_lincoln_nude.jpg'
 gpg: Signature made Wed Nov 14 09:10:08 2018 CET using DSA key ID 70C9B100
 gpg: Good signature from "Angel <angel@triptico.com>"

Summary

For signing text (will ask for sender's passphrase):

 gpg -s --clearsign < msg.txt > msg.signed.txt

For checking a signed text (no passphrase needd):

 gpg < msg.signed.txt

For encrypting text (no passphrase needed):

 gpg -e -a -r user@destination < msg.txt > msg.encrypted.txt

For decrypting an encrypted text (will ask for receiver's passphrase):

 gpg < msg.encrypted.txt

For encrypting and signing text (will ask for sender's passphrase):

 gpg -e -a -r user@destination < msg.txt > msg.both.txt

For decrypting and checking text (will ask for receiver's passphrase):

 gpg < msg.both.txt

For signing binary files (will ask for sender's passphrase):

 gpg -ab binary_file

For checking signed binary files (no passphrase needed):

 gpg binary_file.asc

End notes

Harry can sleep peacefully because he always encrypt and sign his email messages.

Though the examples here are given using GPG version 1, you should really use version 2 (the executable is called gpg2 in those systems that deploy both versions). I've used the older version because one of the features of version 2 is that it includes an agent that asks for passwords in GUI dialogs (if a GUI is available) and retains them for reasonable periods of time. This is of course convenient, but it may make less clear the cases where a passphrase to the keyring is needed.


Ángel Ortega <angel@triptico.com>

A simple pseudorandom number generator

Recently, a member of a game development mailing list asked me what random number algorithm I used in the Space Plumber game. This small document describes it.

First, I want to remember everyone that real random numbers are impossible to create on a computer because computing is deterministic BLAH BLAH BLAH I JUST WANT THE FUCKING CODE.

Ok, here it is:

 unsigned int sp_random(unsigned int *seed, unsigned int range)
 /* Space Plumber's random */
 {
     *seed = (*seed * 58321) + 11113;
     return (*seed >> 16) % range;
 }

It accepts two arguments:

seed
a pointer to an integer containing the random seed. If you only need one, you can use a global value. As a start fill it with the output of time() or something like that.
range
The maximum value to return, plus 1. The maximum range is 65535.

The sp_ in the name, unsurprisingly, comes from Space Plumber. It's not written exactly this way there, though.

The output value will be an integer from 0 to range-1, sufficiently unexpected to be used as a random number in games and such (don't make me laugh about cryptographically-secure values).

It's based on the wrapping of the 32 bit multiplying operation, so it won't work with floating point arithmetic.

From C to C++: A quick reference for aging programmers

So you were a great system programmer, back in the old days; your low level programs were celebrated by clever people, you loved C pointers and some days even considered Assembler as an option. You were happy and self-confident. But somehow you screwed something, got trapped in a time vortex and you ended today, trying to maintain or develop a program using that pesky Object Oriented Programming model in something called C++. I understand you; follow this guide and learn a bunch of things that will put you out of your misery and understand this brave new world.

More...

Artemus 5 Templating Language Overview

Artemus is a template toolkit. It filters text files, parsing, compiling and executing code surrounded by special marks (leaving the rest untouched) and concatenating everything as output. Its main purpose is to filter HTML files, but it can be used for any scripting need related to text filtering and substitution.

More...

MPSL Function Library Reference

This reference documents version 2.2.0 of the MPSL Function Library.

More...

MPSL Overview

MPSL (Minimum Profit Scripting Language) is a programming language concieved as a scripting engine for the Minimum Profit Text Editor, though it can also be used as a general-purpose programming tool.

More...

Minimum Profit character encoding support

This document describes the character encodings supported by the Minimum Profit text editor and the performed autodetection tests.

More...

Minimum Profit Keycodes

Table with Minimum Profit's keycodes and their default assigned actions.

More...

Una amistosa introdución a la codificación de vídeo, parte 3: sonido con pérdida

Por Mark Pilgrim, traducción de Ángel Ortega. Artículo original: http://diveintomark.org/archives/2008/12/30/give-part-3-lossy-audio-codecs

More...

LWN: Btrfs apunta a su inclusión

Por Jonathan Corbet, traducción de Ángel Ortega. Artículo original: http://lwn.net/Articles/313682/

More...

Una amistosa introdución a la codificación de vídeo, parte 2: vídeo con pérdida

Por Mark Pilgrim, traducción de Ángel Ortega. Artículo original: http://diveintomark.org/archives/2008/12/19/give-part-2-lossy-video-codecs

More...

LWN: Btrfs, ¿incorporarlo al núcleo principal?

Por Jake Edge, traducción de Ángel Ortega. Artículo original: http://lwn.net/Articles/302251/

More...

Una amistosa introdución a la codificación de vídeo, parte 1: contenedores

Por Mark Pilgrim, traducción de Ángel Ortega. Artículo original: http://diveintomark.org/archives/2008/12/18/give-part-1-container-formats

More...

El algoritmo Diffie-Hellman

El algoritmo Diffie-Hellman permite que dos partes, comunicándose mediante un canal no cifrado, se pongan de acuerdo en un valor numérico sin que un tercero, que tiene acceso completo a la conversación, pueda conocerlo o calcularlo, al menos en un tiempo práctico.

More...

Gruta FAQ

This is a list of Frequently Asked Questions about the Gruta web content management system.

More...

Gruta Installation Guide

This document contains a brief guide for the installation of Gruta, the web content management system.

More...

Gruta - command line tool

Manipulates Gruta sources directly.

More...

Minimum Profit Action Reference

Minimum Profit actions are editor commands that can be directly bound to the menu or a key.

More...

MPSL internals

This document describes some internal details of this MPSL implementation.

More...