Send Encrypted binary data via an RPC?

Has anybody had any luck sending binary data via an RPC? I want to send an FArchive to the Server and the Client, but am unsure how to go about the encryption.

Essentially, the Server is requesting saved data from the client. This data is related to their level and experience in the game, so it’s important to try and prevent tampering with the outgoing packets. It should be fairly easy to encrypt / decrypt a binary stream based on a key right?

The main question is however - how can I send this data? I’m not sure if FArchive will even work properly.

I kind of alluded to this on Twitter, I think, but one of the reasons that my development existence is awful and miserable the last few weeks is that I’m using JSON files for all of my configuration/loadout/data files – so they’re currently not ever treated as UASSETs at all.

I was looking earlier for something that may be relevant for you (though likely not, as it’s not a super trivial change), but this is what I’ve been thinking about: http://bsonspec.org/

You could make it a static array of bytes (unsigned char). Be aware that the RPC has a limited packet size so your buffer would need to be fairly small (ideally under 1K).

There are various packet encryption modules already available in-engine (Blowfish, AES, XOR). I’d be more concerned with the user altering the data BEFORE its sent (assuming this save data exists on disc) than someone decrypting packets. If that file itself is AES encrypted and your all your packets are encrypted via the block modules - then you’re probably fine.

Check out PacketHandlers/EncryptionComponents for all the various types.

Thanks all,
@botman99 - Good to know. I should be fine, since this is mainly so I can create a plugin and use RPC’s to send different data depending on project, but at most it should just be a few integers. Only thing is, can you send unsigned char via RPC? I had a feeling RPC’s only allow you to send types that work with reflection (maybe an FString in that case?)

@ExtraLifeMatt - Yeah the data is loaded from a Save File then sent (player XP / rank etc.) - In theory it shouldn’t be too hard to encrypt the save file either. I’m not sure if I can stop them modifying the data in-memory, unless I store the data encrypted in memory and only ever decrypt on the Stack when required? Seems a tad excessive but hey… maybe necessary.

I had a look at the FAES.cpp file, but one thing I’m confused about - how do I convert the data to a String so that AES can use it? I guess just create a new unsigned char -> TChar -> FString? not entirely sure on that one.

@TheJamsh, There’s a reason why people tend to use Server Client and just keep clients as dumb terminals. Everything the client sends is suspect to hacking. :slight_smile:

If you’re going for a drop in/drop out type of co-op where the server can’t have a database of all that info, then I would just do what you can to encrypt things like the save file and network traffic - but leave it at that. You aren’t going to prevent people from going through every bit of data on the client with a hex editor or a packet sniffer. Cheaters gonna cheat.

Look at the UGameplayStatics::SaveGameToSlot and UnrealPak::CreatePakFile for examples on applying AES to a buffer.

Ah great stuff, thanks :slight_smile:

The SCUE4 project could come handy on that part along with the prevention of running most of the cheating apps in the background to avoid the interventions in memory. While this can come very handy it still is important to point out the fact that any encryption solution is just as secure as the weakest point of the chain is, which in this case looks to me like the static file (encrypted or not) saved on the disk since it can be edited/decyphered in comfort while nothing will prevent the user to do so. Client side preventions will last for a limited time only, and they gets defeated eventually.

The server can actually make a few api calls to retrieve these informations from a trusted source (not public), and this will be a very simple rest server attached to a mysql. Any reason to not doing this?

To be a little more efficient, a secondary option would be to allow the client to send this savegame without any encryption, but on the server side you make a quick md5 hash comparison to check it’s integrity (valid or not). It won’t be a good idea to store this checksum hash in the savegame, but if the server can generate the same savegame file (binary contents must match) it can also produce the hash upon endgame and just put it to the rest server to retrieve it later.

Certainly do-able, but means I have to maintain a MySql database somewhere on a server which has inherent cost of it’s own - it could be worth looking into I guess.

This is mostly becoming a discussion about the best way to store the data now :stuck_out_tongue: There is one other issue I have though, there are currently no plans for dedicated servers - which means Servers are perfectly capable of hacking their own game data since it’s all available to them. At that point, the MySql stuff seems a little redundant.

Yes i agree on that too, and in this case the situation is more like p2p gaming related, where the game server is no longer a trusted server but an another suspicious client only. However the problem here is still the same, that any client can cheat and this must be eliminated as much as possible. If you wish to reduce the chances of the server side interventions, you can maybe run dedicated server instances on the client machines, but these instances are for totally unrelated players only, and so the client would never be allowed to join that match, thus no reasons to manipulate the results there.

Anyway, as for p2p i think of a “majority vote” kind of solution to simply decide who is telling the truth. What if, the clients will submit the match results of all the participants to the rest api at when the match ends? At the rest server side you can decide which information is the legit (here comes in the majority’s rule), and store the only informations that have the highest matching from all participants, thus it must be very likely to be true. It would only work for more then 2 players matches, but this way the players have very little chances to cheat, or not at all. The only caveat here is when the server is having false informations from all the participants, in which case you can maybe accept player’s own result or simply just dismiss the match results. This solution still require a third party rest server to store the player profiles, but at least you can have very high chances that its content is true all the time.