Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411428 Posts in 69363 Topics- by 58416 Members - Latest Member: JamesAGreen

April 19, 2024, 01:56:43 PM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)Simple DRM Idea for HTML5 Canvas
Pages: [1]
Print
Author Topic: Simple DRM Idea for HTML5 Canvas  (Read 1531 times)
Samaras-Sama
Level 1
*


samy is my hero


View Profile
« on: January 07, 2018, 02:28:36 PM »

I come from somewhat of a security background. I was thinking of a fast way to protect images in HTML5 applications.



The idea is pretty simple.

Before game compilation

1. Generate a chaotic map, such as the logistic map.
2. Xor your intended image with the chaotic map. This gives you an encrypted result.
3. Save the xor'ed result to a lossless image format, as the original image file.

At runtime

4. Set the context's composite operation to 'source-over'
5. Draw the portion of the chaotic map that you used to encrypt the image to the canvas.
6. Set the context's composite operation to 'xor'
7. Draw your encrypted image to the canvas from earlier.
8. Grab a coffee and smile.

The idea is that an un-encrypted copy of the image is never in RAM at anytime, unless within the memory used for the screen. Of course, they can always rip our graphics from the screen memory (The canvas that's displayed) but modifying our graphics will be highly difficult unless they understand the scheme.

Adding some Fragility to our Scheme:



(Discrete Cat Map, from Wikipedia)

Fragility means one small change leads to a large change. Fragility is very good for DRM. Fragility means our image will be super-sensitive to small modifications, one small change will corrupt the scheme. If a hacker is clever and tries to mess with our image, manipulating pixels will only break the image and prevent the correct image from displaying.

We could probably take our original image use the discrete arnold map before xor-ing it with the logistic map (The arnold map is a chaotic map that makes an orderly image very chaotic in a few discrete steps)

The result of using the discrete arnold map is that in the image's chaotic state, any change by an attacker made to the image will completely ruin it unless the arnold map is first performed to bring our image back to order again.

Preventing Substitution

This scheme already does a fairly good job at preventing attackers from substituting their own images in place for ours, effectively modding our game.

We can also however take advantage of redundancy, which is a fancy way of saying "extra space" inside of images.

Now, there are tons of image watermarking and image steganography schemes, so I won't go into them. They're too complex to discuss here and I promised that I would keep this simple.

For this you could use anything from getImageData() to read the hidden data from the image's pixels, btoa()/atob() (Which would get the base64 Data URI of the image allowing you to explicitly read data in the metadata fields of the image, *but this isn't very secure* or rollout your own image parser to read the pixel data.

Watermarking/stegano schemes can be used to encode side information within the image that could be used as a form of digital watermark.

For instance, if you encode a string within an image, in Javascript, you could load this string with Function() or eval() (Please don't use eval(), for the love of Jesus  Evil)

This would let you run code that could possibly be used to validate not only the authenticity of the image, but it could also be used to secretly house critical code of the game, such as code used for databases, or in-app purchasing.

With the above methods, removing or modifying an image would now be as serious as corrupting the game's core code, and small modifications would range anywhere from corrupting the graphics, to causing the game to crash or flagging an anti-tamper mechanism.

Downsides

The main downside is that transparency isn't supported (You also need a lossless format like PNG and at least with the way that I'm envisioning this transparency won't work), and I'm sure if someone REALLY wanted to modify your game with their own graphics they could easily do so by directly modifying the image source of drawImage() calls directly in your source code if your calls were visible there.

This method however would force a novice Javascript hacker to have a copy of your encrypted assets within memory which would be very useful for proving that their property was stolen from yours.

If an attacker tried to just comment out your calls to drawImage and instead included calls their own graphic sources (Likely to make a mod of your game), they would still need your encrypted information to still be there unless they were clever enough to recreate the missing information added by new Function().

You could use this to possibly threaten them to remove the stolen property or face legal action, proving that it's yours.

However I guess this would mainly just make it super difficult, but not impossible to someone who

1.) Understands your scheme or at least what it tries to do.
2.) Knows Javascript to a degree and knows how new Function() works.
3.) Is patient and willing enough to inspect your code at every step and try to recreate the missing pieces.

There's also a bit of overhead. Ignoring the xor and other fun chaotic map madness. You'll have to make 2 calls to drawImage() for each decryption instead of one, all assuming you decrypt your image on each frame and you don't cheat and try to cache the decrypted result to another offscreen canvas.

...

Please leave your thoughts... I don't have anyone to discuss this with (To most people around me, this stuff is like Greek to them), I wonder if someone on these forums recognizes what I'm trying to do.
« Last Edit: January 07, 2018, 02:45:05 PM by Oekaki-Sama » Logged

Devlog<br /><br />[/
Samaras-Sama
Level 1
*


samy is my hero


View Profile
« Reply #1 on: January 07, 2018, 05:32:57 PM »

Okay, I've tried out this idea:

The xor globalCompositeOperation seems to only modify the alpha channel of an image.

It seems to be alpha channel based rather than color channel based.

One could logically perform a bitwise xor on a TypedArray of pixel data found by using getImageData and putImageData but these Javascript functions should be avoided and I want to avoid using them at all costs.

EDIT:

Here's how I'm getting this to work

Generating the chaotic map for HTML5:

So the 'xor' gCO mode works slightly differently than what I was expecting, but it doesn't matter because it still works for what it's needed to do.

1. Generate a 2D chaotic map (logistic)

2. Set the 1 value to Alpha 1.0 and the 0 value to Alpha 0.0

3. Draw the map onto a blank canvas.

4. Set the gCO to 'xor'.

5. Draw your graphic on top of the generated chaotic map. Make a note of the location of this.

6. Set your gCO back to 'source-over'

7. Invert the 2D chaotic map (Set all 255 areas to 0 and all 0 areas to 255)

8. Draw this inverted region onto another area of the canvas

9. Set your gCO back to 'xor'

10. Draw your original image over this new inverted chaotic map, at the exact corresponding position in the first map. Make another note of this location.

You can store the graphics at the two locations as their own separate images if you want, but I kept them on a canvas.

Decrypt/De-obfuscate: To get the source image:

10. Set your gCO to 'source-over'

11. Draw either of your two generated images to a new canvas, sourcing it from your logistic map canvas.

10. Set your gCO to 'xor'

12. Draw the remaining generated image in the exact location in the new canvas.

Of course, the security of this scheme if done this simple way is very weak, but I'm just trying to show at least what can be done. We can add many better modifications to improve this scheme. All we're doing at the moment is literally adding two scrambled images together to get a clean image and it isn't hard for an attacker to figure this out.  Smiley The important thing at least is that it seems to be very fast.

Let me play with this further. I have many ideas for some cool things that can be done with this with a little investigation, possibly even building an entire anti-tampering DRM system from the ideas stated above.

The point of this was never to prevent people from stealing your images (this will happen no matter what you do), but you can build off of this for a content validation system, game and code watermarking, and even hiding important side channel information that you don't want to be tampered with.
« Last Edit: January 07, 2018, 08:35:25 PM by Oekaki-Sama » Logged

Devlog<br /><br />[/
bateleur
Level 10
*****



View Profile
« Reply #2 on: January 09, 2018, 09:04:27 AM »

I'm not a security expert, so excuse me if this is a bit of a noob question, but why is it OK to assume here that the attacker can't simply change the code to not use XOR (and then replace the image easily)?

I mean, if the attacker really can't read the code then wouldn't it be a much simpler approach to just take a hash of the image and compare with expected values compiled into the code? That would result in much better performance whilst requiring less code, less complexity and potentially even being harder to hack because you can hide the check anywhere.
Logged

Samaras-Sama
Level 1
*


samy is my hero


View Profile
« Reply #3 on: January 09, 2018, 09:48:37 AM »

I'm not a security expert, so excuse me if this is a bit of a noob question, but why is it OK to assume here that the attacker can't simply change the code to not use XOR (and then replace the image easily)?

Quote from: Oekaki-Sama
If an attacker tried to just comment out your calls to drawImage and instead included calls their own graphic sources (Likely to make a mod of your game), they would still need your encrypted information to still be there unless they were clever enough to recreate the missing information added by new Function().

It wouldn't be hard for them to add their own code. This is Javascript. Smiley The scheme forces them to have the images however, since the code needed to execute the game is within the images. You can add your own calls to drawImage, but if I get suspicious that you're using a copy of my source without permission and I look inside of the package, there's a very high chance I'll still find my unedited images, giving me a case to get this counterfeit removed.

I mean, if the attacker really can't read the code then wouldn't it be a much simpler approach to just take a hash of the image and compare with expected values compiled into the code? That would result in much better performance whilst requiring less code, less complexity and potentially even being harder to hack because you can hide the check anywhere.

That has some issues:

How are you comparing hashes? Are you generating MD5 or SHA-1 hashes, then comparing them and setting a flag (like a boolean or a value) to indicate that they match?

When are you generating hashes? Is it at compile time? Is it dynamic or generated at some point within the program's execution? Are you generating a unique hash for each player based on some content authority like a software fingerprint?

It matters because even if your attacker can't understand the code, they can always still read it. This is Javascript! Smiley Outside of Javascript, the average attacker doesn't understand code. One method they could use is substituting another image for ours and comparing where the two program control flows differ (Where the hashed values fail) will lead you to where the hashes are compared, no matter where you've hidden the comparison and will expose this scheme.

Obfuscation or spaghetti code could slow this down but would be prolonging the inevitable. In addition, if you're only setting a flag, once I find it, I could possibly just modify this flag directly or as you mention, add code that just avoids it altogether.

Our above scheme works no matter how many crazy modifications are used to try and circumvent it. Even if you write Javascript code to try and avoid drawing our images, the presence of these images is still vital for operation of our program. No matter what, vital game code is within our image, the images are still in the asset folder, and the asset folder is all we need to make a case of theft. If someone tries to get the better of us and modifies the images (either to modify the game or modify the vital code within them) this will also break the game.

Unless an attacker is patient enough to reconstruct the missing pieces within the image piece by piece by looking at what code statements are being executed after being retrieved (From reversing the watermark scheme) from the image, it serves as a strong barrier to conceal our game, create an anti-tamper mechanism to our watermark, and an even stronger software birthmark that can prove that fraudulent copies of our game in the wild really belong to us.
Logged

Devlog<br /><br />[/
quantumpotato
Quantum Potato
Level 10
*****



View Profile WWW
« Reply #4 on: February 20, 2018, 08:31:15 AM »

Well, that's interesting.
Curious if you implement it and see how it goes.
Piracy is still an issue for webgames but most of the money now is in microtxs, requiring server validation etc
Logged

Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic