Search code examples
c#cryptographyencryption-asymmetric

Max Length and Message Too Long error for Asymmetric Encryption in Unity


I use Asymmetric Encryption from Here and I was able to get things working perfectly as I turn my classes that hold data to Json data with JsonUtility.ToJson() and then I use the Encryption in the link above.

I use to use the C# Serializer but ran into issues so I was directed to using this which is working out great but when I changed one of my saving systems with this I run into the error of "Max Length is 117" which makes me think I am saving too much in my class (I have variables for the Transform, Sprite Renderer and Collider2D) so I increased my keySize variable (using 1024 for this and all my other areas I use this as well.) from 1024 to 2048 in my EncryptText() and DecryptText() methods in the Asymmetric Encryption link and saw what I thought was working as I was getting to the point where I had a big enough size to hold the data from what one of the throw error messages was telling me.

I then reached a point where it said "CryptographicException:message too long" and now I am wondering, "how do I fix this?". This makes me worry if I put this in one of my projects in the Unity Store to where people will run into the issue of saving too much in a scene (and it was about 4 GameObjects being saved lol... :( ). Even if I broke what I saved up into multiple classes and saved it that fashion I feel like the size issue could potentially be a red alert.

Any ideas on how to approach this situation?

Code :

public class State_Manager : MonoBehaviour {

    public void Save()
    {
        // IF we have nothing to save then don't save.
        if(transformStateList.Count == 0){
            return;
        }
        // Create a new State_Data.
        State_Data data = new State_Data ();
        // Loop the amount of the size of the List.
        for(int i = 0; i < transformStateList.Count; i++){
            // Create a new Object_Data struct.
            Object_Data objectData = new Object_Data ();
            // Store our data in our data structure.
            objectData.StoreData(transformStateList[i]);
            // Add it to the list.
            data.objectData.Add (objectData);
        }
        // Turn the Store_Data into Json data.
        string stateToJson = JsonUtility.ToJson(data);
        // Encrypt the Json data.
        string encryptedJson = AsymmetricEncryption.EncryptText (stateToJson, keySize, PlayerPrefs.GetString("PK"));
        // Save the information.
        PlayerPrefs.SetString("State", encryptedJson);
    }

    [System.Serializable]
    class State_Data
    {   
        public List<Object_Data> objectData = new List<Object_Data> ();
    }
}

[Serializable]
public class Object_Data {

    // Transform information.
    public bool active;
    public string name;
    public int layer;
    public float xPos;
    public float yPos;
    public float zPos;

    // Sprite Renderer Information
    public string spriteName = "";
    public string sortLayerName = "";
    public int sortLayerOrder = 0;

    // Collider2D Information.
    public bool isCollider = false;
    public bool activeCollider;

    public void StoreData(GameObject go){
        // Save the activeness.
        active = go.activeInHierarchy;
        // Save the GameObjects name.
        name = go.name;
        // Save the GameObjects layer.
        layer = go.layer;
        // Save the GameObjects position.
        xPos = go.transform.position.x;
        yPos = go.transform.position.y;
        zPos = go.transform.position.z;
        // IF this GameObject has a sprite renderer,
        // ELES it doesn't have a sprite renderer.
        if (go.GetComponent<SpriteRenderer> () != null) {
            // Save the sprite name, sorting layer name and the sorting layer order.
            spriteName = go.GetComponent<SpriteRenderer> ().sprite.name;
            sortLayerName = go.GetComponent<SpriteRenderer> ().sortingLayerName;
            sortLayerOrder = go.GetComponent<SpriteRenderer> ().sortingOrder;
        }
        // IF there is a Collider2D attached,
        // ELSE there is not a Collider2D attached.
        if (go.GetComponent<Collider2D> () != null) {
            isCollider = true;
            activeCollider = go.GetComponent<Collider2D> ().enabled;
        }
    }
}

Solution

  • You don't use asymmetric encryption to encrypt large amounts of data. If you have large amounts of data you normally use symmetric encryption then use asymmetric encryption to encrypt the key.

    However, that is totally overkill for your purposes. From how your code looks it appears you likey just have two fields for the public and private keys in your player perfs and you are just encrypting a "State" that will be read out later. Don't use asymmetric encryption for that, just use symmetric encryption.

    If you really are wanting to use asymmetric encryption what you will need to do is for encryption:

    1. Generate a new random symmetric encryption key every time you encrypt the data.
    2. Encrypt your data symmetrically with the random key.
    3. Encrypt the random key with your public key from the asymmetric encryption.
    4. Store the symmetrically encrypted data and the asymmetrically encrypted random key together somewhere.

    For decryption:

    1. Load the symmetrically encrypted data and the asymmetrically encrypted key from somewhere.
    2. Decrypt the asymmetrically encrypted key with your private key from the asymmetric encryption.
    3. Use the decrypted symmetric key to decrypt the data
    4. Use the data.