Encrypt data within mobile app and send to web service

You can't. This is a fundamental principle of general purpose computing.

You're running into Shannon's maxim:

The enemy knows the system. One ought design systems under the assumption that the enemy will immediately gain full familiarity with them.

Just to make my point completely clear: you're giving someone a car, and asking them to only ever drive to one particular place. Nothing stops them from deciding to go somewhere else - you're relying on them adhering to your request.

If your security mechanism hinges on the hope that someone won't look at your executable and discover your encryption method / embedded keys, then it is not a security mechanism; it is an obscurity mechanism.

From what I can tell, you're trying to enforce that users are within a specified area via GPS coordinates, and also want to ensure that they don't spoof those coordinates. This cannot be done on a general purpose computing platform such as a smartphone. Let's look at the technology stack:

  • Your webapp sits in "the cloud" somewhere. You control this entirely.
  • Your app sits on a phone. You have minimal control over this, if any. Possible attack vectors include reverse engineering, app modification, direct webapp requests, memory editing, etc.
  • The smartphone OS (e.g. Android or iOS) runs on the device. You have no control over this. This is responsible for communicating with the GPS device and translating data into usable coordinates. Possible attack vectors include: fake GPS coordinates via test panel (most phones have this feature), modified GPS driver, hooked GPS APIs, etc.
  • The GPS module is inside the device. You have no control over this. The GPS module is responsible for communicating with GPS satellites and relaying the data to the CPU via a standard bus. Possible attack vectors include: man-in-the-middle on the bus, replacement fake GPS module, fake GPS satellite signal from software defined radio, etc.

So you cannot enforce that the GPS coordinates you receive into your webapp are correct, since they might have been tampered with at the app level, the OS level, the hardware level, or even the GPS signal level. Or, barring all that, someone might just skip the phone entirely and manually send requests to your webapp containing phony data!

The solution is to accept the risk or change your security model.


You should always use SSL.

SSL has a public key built in, and provides for "authentication", meaning it ensures that the server you're communicating with is actually the webservice you want, and not some impostor.

Since you don't indicate otherwise, or any other need you have, I think SSL will solve all your concerns about sending data to a server and securing it in transit.


Update

Based on your updated requirements in the comments, I understand you want to prevent spoofing of the GPS data sent to your webservice.

If you have no control over the device (administrative or otherwise) what @Polynomial says is correct. If you are creating a closed system, embedded, or are in a corporation you may have more options.

Suppose you have full control of every phone your application will run on. That means locking the phone down, maintaining exclusive control of the admin password and never give it to the end users.

Next, you can assign each device a unique key to encrypt the data to be sent to a web service.

If a given phone is compromised, you will be able to determine which device it was based on the key used.


The best practice depends on the exact usage.

What I gather from your question is that you have an app which sends you GPS data and time, like a "footprint" application. You want to ensure that you are not being fed false data, and so you want to ensure that the data is coming from your real client and not a fake.

Well, unfortunately as other answers have stated, that is impossible. Given the APK file for your app, someone can quite feasibly decompile it into Java source code, possibly not as elegant as your own source, but definitely workable. They can then use your code to build their own app, that communicates with yours in exactly the way you expect, and use it to feed you false data.

Therefore, whatever scheme you use for data transport should never trust the client. It should instead trust the user.

Consider this solution; your app server is signed with a trusted public-key certificate (it could, in this circumstance, be trusted for the sole reason that your application knows the exact certificate it should be given; this is called "certificate pinning" and it works whether you got the certificate signed by a global CA or not). Upon request, it presents this certificate to whomever asks for it; it's public information, you could plaster this thing on every hacker forum on the Internet and it would be no less secure. Your client uses this certificate to negotiate a secure communications tunnel; this is pretty standard stuff.

Now, you have confidentiality. You need authenticity; it doesn't matter that nobody else can listen to the conversation between the two of you if you don't know for sure who's on the other end. So, once the channel is open, the next thing you expect is an authentication request containing user credentials. You should reject any request to send GPS data if the session has not been authenticated. The credentials the user supplies in such a request could be their username and password, their phone's IMEI or MAC address, the 10-digit code from a crypto key fob, whatever you think is necessary to properly ensure that only a particular user could be able to provide those credentials.

Once you have those credentials and have verified that they match expectations, however you want to do that, you send them back an "authentication token". This is as simple as a random number distinct from that used for any other open session. A V4 GUID's a pretty good choice as well. This identifier will be required as part of any request to send or receive data on this channel during this session, it will only be accepted on this particular channel, and only as long as this unique session is open.

Once all this is set up, any service call that was made over that session's secure channel that includes the correct authentication token can generally be trusted. You should probably include one more thing, which is a measure to guard against replay attacks. An attacker doesn't have to know exactly what's being sent back and forth to mess you up by simply repeating what has already been said. So, to ensure that your system only deals with a unique message one time no matter how many times it's sent, each message should include a nonce, a unique value used one time. A simple sequence counter value, forming part of the request structure and encrypted by the secure channel, should suffice for this; then, all you have to do is ignore any message whose sequence number isn't the next one you expect to receive from the client (there can be some fault tolerance inherent in this, but never accept the same type of service request from the same client with the same sequence number twice).