0

I am sending byte[] as encoded string through Android app. They way I am converting my byte[] is as follows (Basically byte[] is the thumbscan/fingerscan image): Android

byte[] imageData = m_left_enrollment_fmd(); // returns byte[] which is OK!
// Base64 belongs to android.util package
String forJson = Base64.encodeToString(imageData , Base64.DEFAULT);

And this is how I am decoding it on Server side (Java):

// Base64 belongs to java.util package
byte[] imageData = Base64.getDecoder().decode(sqlJsonParams.optString("IMAGE_DATA"));

It generates following exception:

]] Root cause of ServletException. java.lang.IllegalArgumentException: Illegal base64 character -1 at java.util.Base64$Decoder.decode0(Base64.java:714) at java.util.Base64$Decoder.decode(Base64.java:526) at java.util.Base64$Decoder.decode(Base64.java:549) at org.skm.webresources.mobilehis.v2.Fingerprint.getByteArray(Fingerprint.java:470) at org.skm.webresources.mobilehis.v2.Fingerprint.postFingerprint(Fingerprint.java:86) Truncated. see log file for complete stacktrace

  • Question 1: What I am doing wrong?
  • Question 2: Is it the correct way to send byte[] in REST Service?

The Q&A I have seen so far are as follows:

Faizan Mubasher
  • 4,427
  • 11
  • 45
  • 81

2 Answers2

0

I've sent images as multipart, maybe it will help:

ArrayList<MultipartBody.Part> list = new ArrayList<>();
        File photo = new File(image_uri);
        RequestBody file = RequestBody.create(MediaType.parse(getMimeType(photo.getAbsolutePath())), photo);
        MultipartBody.Part partImage = MultipartBody.Part.createFormData("image", photo.getName(), file);
        list.add(partImage);
        Call<Void> call = api.uploadMyImage(agreement, list, "@");

getMimeType():

public static String getMimeType(String url) {
        String type = null;
        String extension = MimeTypeMap.getFileExtensionFromUrl(url);
        if (extension != null){
            type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
        }

        return type;
    }

to Base64:

public static String convertToBase64(String path) {
        Bitmap bm = BitmapFactory.decodeFile(path);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bm.compress(Bitmap.CompressFormat.PNG, 100, baos);
        byte[] byteArrayImage = baos.toByteArray();
        String encodedImage = android.util.Base64.encodeToString(byteArrayImage, android.util.Base64.DEFAULT);
        return encodedImage;
    }
SkypeDogg
  • 1,000
  • 2
  • 13
  • 28
0

I ran into this issue as well. Looking at Android and Java's base64 API's, they both follow RFC 2045 but Java's version also follows RFC 4846 which has this small catch:

MIME [4] is often used as a reference for base 64 encoding. However, MIME does not define "base 64" per se, but rather a "base 64 Content- Transfer-Encoding" for use within MIME. As such, MIME enforces a limit on line length of base 64-encoded data to 76 characters. MIME inherits the encoding from Privacy Enhanced Mail (PEM) [3], stating that it is "virtually identical"; however, PEM uses a line length of 64 characters. The MIME and PEM limits are both due to limits within SMTP.

Implementations MUST NOT add line feeds to base-encoded data unless the specification referring to this document explicitly directs base
encoders to add line feeds after a specific number of characters.

Your Android's base64 encoder is doing a line feed after 76 characters while Java's encoder is expecting no line feeds at all. The way to handle this on Android's side is to use the no_wrap option and then it can be read by your Java server:

String forJson = Base64.encodeToString(imageData , Base64.NO_WRAP);

Now it will read fine. This is the output of option Base64.DEFAULT:

ZI4069Ue3D5Ikbp93eJ/r6HQG3CPj3FxGE1SoywcgCuaJ0t5M/D79utSyF1Uf7C7NHdQ9fGuHQ2P\nJnNpsHAEpA==

versus the output of Base64.NO_WRAP:

ZI4069Ue3D5Ikbp93eJ/r6HQG3CPj3FxGE1SoywcgCuaJ0t5M/D79utSyF1Uf7C7NHdQ9fGuHQ2PJnNpsHAEpA==