Hi! This post is intended to help other developers to protect their 3D assets. Many of you are interested in protecting your assets, especially your 3D models as we can see in the forum here:
- How to protect my web app (scripts, models)?
- Suggestions on how to protect 3D data
- [ENGINE ONLY] General question about assets and scenes
I was asked to find a solution to protect 3D models. We all know that with web technology, we need to distribute the resources on user devices to get them displayed. So I decide to see if there’s a way to encrypt my 3d models and made them readable only from my own applications (with minified and obfuscated code). Still, my method is not 100% proof, but will require considerable effort to steal my models.
I will share you the idea behind this and some code, but I can’t share you my complete recipe, obviously for security reason.
Thanks to @yaustar and his help about this question: [SOLVED] How to create an Asset from file content stored in variable?. Using this code mean that it is possible to read a GLB file from a variable or even from a database (check the size of your GLB before going there).
So, this also open the possibility to get your GLB from anywhere. In my case, I still store the 3D models in files but not in a GLB, in a custom file extension! Yep, just rename your glb file to anything else. This will hide to others that your are using GLB.
Also, another protection I add on top of that, is by changing the binary of the file, to make it intentionally not usable. You will need some binary comprehension to go there. I did explore and changed the binary of a my new custom glb file using this Free hex editor. Note the position and the value of what you changed in this file, store that somewhere, because you will need that later.
Now, you have a new custom file like this “my3dModel.yourExtension” that is not usable.
At runtime, you need to load this file by using the binaryHandler from the Playcanvas engine.
this.app.loader.load("/my/3d/model.yourExtension", "binary", function (err, data) {
//Data will be an arrayBuffer
//The ArrayBuffer object is used to represent a generic, fixed-length raw binary data buffer.
});
If you load your model from a variable, you will not need to do this step. But hey, it is usufull to have models in files.
Now, you have your model in binary! But remember, the binary was changed to make it unusable. Now, it’s time to fix it by playing with binary again. And for that, you will need to use DataView.
The DataView view provides a low-level interface for reading and writing multiple number types in a binary ArrayBuffer.
From there, you will need to use DataView to access the index of the binary you have changed and but the good value.
var self = this;
this.app.loader.load("/my/3d/model.yourExtension", "binary", function (err, data) {
//Data will be an arrayBuffer
//The ArrayBuffer object is used to represent a generic, fixed-length raw binary data buffer.
//Fixing the binary
var dataview = new DataView(data);
dataview.setInt8(98765, 12345);
var blob = new Blob([data]);
var data = URL.createObjectURL(blob);
//This must end with ".glb"
var filename = 'test.glb';
var file = {
url: data,
filename: filename
};
var asset = new pc.Asset(filename, 'container', file);
asset.once('load', function (containerAsset) {
my_entity.model.asset = containerAsset.resource.model;
});
self.app.assets.add(asset);
self.app.assets.load(asset);
});
Et voilĂ ! You can now display your 3D model in your scene.