I was successfully able to create a stand-alone Java Application that creates Expiring Signed URL's to assets sitting in Google Cloud Storage. However, I have been unsuccessful in figuring out how to create Expiring Signed URL's to these same assets through AppEngine.
How can I create a Expiring Signed URL to Google Cloud Storage Assets that I can return to client applications?
Here is my Java Application that works:
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.UnrecoverableKeyException;
import java.util.Calendar;
import org.apache.commons.codec.binary.Base64;
public class GCSSignedURL {
public static void main(String[] args) throws Exception {
    final String googleAccessId = "XXXXXXXXXXXX@developer.gserviceaccount.com";
    final String keyFile = "D:\\XXXXXXXXXXXXXXXXXXXXXXXXXXXXX-privatekey.p12";
    final  String keyPassword = "notasecret";
    Calendar calendar = Calendar.getInstance();
    calendar.add(Calendar.MINUTE, 30);
    String httpVerb = "GET";
    String contentMD5 = "";         
    String contentType = "";
    long expiration = calendar.getTimeInMillis();
    String canonicalizedExtensionHeaders = ""; 
    String canonicalizedResource = "/myproj/foo.txt";
    String stringToSign = 
            httpVerb + "\n" + 
            contentMD5 + "\n" + 
            contentType + "\n" + 
            expiration + "\n" + 
            canonicalizedExtensionHeaders + 
            canonicalizedResource;
    PrivateKey pkcsKey = loadKeyFromPkcs12(keyFile, keyPassword.toCharArray());
    String signature = signData(pkcsKey, stringToSign);     
    String baseURL = "https://storage.cloud.google.com/myproj/foo.txt";     
    String urlEncodedSignature = URLEncoder.encode(signature, "UTF-8");
    String url = baseURL + "?GoogleAccessId=" + googleAccessId + "&Expires=" + expiration + "&Signature=" + urlEncodedSignature;
    System.out.println(url);
}
private static PrivateKey loadKeyFromPkcs12(String filename, char[] password)
        throws Exception {
    FileInputStream fis = new FileInputStream(filename);
    KeyStore ks = KeyStore.getInstance("PKCS12");
    try {
        ks.load(fis, password);
    } catch (IOException e) {
        if (e.getCause() != null
                && e.getCause() instanceof UnrecoverableKeyException) {
            System.err.println("Incorrect password");
        }
        throw e;
    }
    return (PrivateKey) ks.getKey("privatekey", password);
}
private static String signData(PrivateKey key, String data)
        throws Exception {
    Signature signer = Signature.getInstance("SHA256withRSA");
    signer.initSign(key);
    signer.update(data.getBytes("UTF-8"));
    byte[] rawSignature = signer.sign();
    String encodedSignature = new String(Base64.encodeBase64(rawSignature,
            false), "UTF-8");
    return encodedSignature;
}
}
Here is what I have tried:
public String signUrl(Long _songId, String _format) throws ResourceNotFoundException
{
    final String googleAccessId = "XXXXXXXXXXXXXXXXXX@developer.gserviceaccount.com";
    AppIdentityService service = AppIdentityServiceFactory.getAppIdentityService();
    Calendar calendar = Calendar.getInstance();
    calendar.add(Calendar.MINUTE, 5);       
    String httpVerb = "GET";
    String contentMD5 = "";
    String contentType = "";
    long expiration = calendar.getTimeInMillis();       
    String canonicalizedExtensionHeaders = "";      
    String canonicalizedResource = "/myproj/foo.txt";
    String stringToSign = 
            httpVerb + "\n" + 
            contentMD5 + "\n" + 
            contentType + "\n" + 
            expiration + "\n" + 
            canonicalizedExtensionHeaders + 
            canonicalizedResource;  
    SigningResult key = service.signForApp(stringToSign.getBytes());
    String baseURL = "https://storage.cloud.google.com/myproj/foo.txt";
    String encodedUrl = baseURL + "?GoogleAccessId=" + googleAccessId + "&Expires=" + expiration
            + "&Signature=" + key.getKeyName();
    return encodedUrl;
}
The result is an expiring URL but requires me to authenticate with my google email / password so the signing isn't working properly.
I was able to finally generate an encoded URL using Fabio's suggestion, however, I now get:
<?xml version="1.0" encoding="UTF-8"?>
-<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated 
does not match the signature you provided. Check your Google secret key and signing 
method.</Message>
<StringToSign>
GET 1374729586 /[my_bucket]/[my_folder]/file.png</StringToSign>    
</Error>
The code I am using to generate the URL is:
AppIdentityService service = AppIdentityServiceFactory.getAppIdentityService();
    final String googleAccessId = service.getServiceAccountName();
    String url = songUrl(_songId, _format);  
    Calendar calendar = Calendar.getInstance();
    calendar.add(Calendar.MINUTE, 10);
    String httpVerb = "GET";
    String contentMD5 = ""; 
    String contentType = ""; 
    long expiration = calendar.getTimeInMillis()/1000L;
    String canonicalizedExtensionHeaders = "";      
    String canonicalizedResource = "/[my_bucket]/[my_folder]/file.png";
    String stringToSign = 
            httpVerb + "\n" + 
            contentMD5 + "\n" + 
            contentType + "\n" + 
            expiration + "\n" + 
            canonicalizedExtensionHeaders + 
            canonicalizedResource;
    try 
    {
        String baseURL = http://[my_bucket].commondatastorage.googleapis.com/[my_folder]/file.png;  
        SigningResult signingResult = service.signForApp(stringToSign.getBytes());
        String encodedSignature = new String(Base64.encodeBase64(signingResult.getSignature(), false), "UTF-8");
        String encodedUrl = baseURL + "?GoogleAccessId=" + googleAccessId + "&Expires=" + expiration
                + "&Signature=" + encodedSignature;
        return encodedUrl;
    } 
    catch (UnsupportedEncodingException e) 
    {
        throw new ResourceNotFoundException("Unable to encode URL.  Unsupported encoding exception.", e);
    }