title: IllegalArgumentException Error with Android Licensing
body: <p>I'm trying a sample app to configure the Google License Service LVL in Android</p>
  
  <p>following the instructions found <a href="http://developer.android.com/guide/google/play/licensing/adding-licensing.html" rel="nofollow">HERE</a></p>
  
  <p>I have just tried to configure a base app with the included code</p>
  
  <pre><code>public class MainActivity extends Activity {
      private static final String BASE64_PUBLIC_KEY = "mykeywithoutspaces";
  
      // Generate your own 20 random bytes, and put them here.
      private static final byte[] SALT = new byte[] {
          -00, 65, 30, -128, -58, -57, 00, -64, 51, 32, -95, -45, 77, -117, -36, -15, -11, 32, -64,
          89
      };
  
      private TextView mStatusText;
      private Button mCheckLicenseButton;
  
      private LicenseCheckerCallback mLicenseCheckerCallback;
      private LicenseChecker mChecker;
      // A handler on the UI thread.
      private Handler mHandler;
  
      @Override
      public void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
          setContentView(R.layout.main);
  
          mStatusText = (TextView) findViewById(R.id.status_text);
          mCheckLicenseButton = (Button) findViewById(R.id.check_license_button);
          mCheckLicenseButton.setOnClickListener(new View.OnClickListener() {
              public void onClick(View view) {
                  doCheck();
              }
          });
  
          mHandler = new Handler();
  
          // Try to use more data here. ANDROID_ID is a single point of attack.
          String deviceId = Secure.getString(getContentResolver(), Secure.ANDROID_ID);
  
          // Library calls this when it's done.
          mLicenseCheckerCallback = new MyLicenseCheckerCallback();
          // Construct the LicenseChecker with a policy.
          mChecker = new LicenseChecker(
              this, new ServerManagedPolicy(this,
                  new AESObfuscator(SALT, getPackageName(), deviceId)),
              BASE64_PUBLIC_KEY);
          doCheck();
      }
  
      protected Dialog onCreateDialog(int id) {
          final boolean bRetry = id == 1;
          return new AlertDialog.Builder(this)
              .setTitle(R.string.unlicensed_dialog_title)
              .setMessage(bRetry ? R.string.unlicensed_dialog_retry_body : R.string.unlicensed_dialog_body)
              .setPositiveButton(bRetry ? R.string.retry_button : R.string.buy_button, new DialogInterface.OnClickListener() {
                  boolean mRetry = bRetry;
                  public void onClick(DialogInterface dialog, int which) {
                      if ( mRetry ) {
                          doCheck();
                      } else {
                          Intent marketIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(
                                  "http://market.android.com/details?id=" + getPackageName()));
                              startActivity(marketIntent);                        
                      }
                  }
              })
              .setNegativeButton(R.string.quit_button, new DialogInterface.OnClickListener() {
                  public void onClick(DialogInterface dialog, int which) {
                      finish();
                  }
              }).create();
      }
  
      private void doCheck() {
          mCheckLicenseButton.setEnabled(false);
          setProgressBarIndeterminateVisibility(true);
          mStatusText.setText(R.string.checking_license);
          mChecker.checkAccess(mLicenseCheckerCallback);
      }
  
      private void displayResult(final String result) {
          mHandler.post(new Runnable() {
              public void run() {
                  mStatusText.setText(result);
                  setProgressBarIndeterminateVisibility(false);
                  mCheckLicenseButton.setEnabled(true);
              }
          });
      }
  
      private void displayDialog(final boolean showRetry) {
          mHandler.post(new Runnable() {
              public void run() {
                  setProgressBarIndeterminateVisibility(false);
                  showDialog(showRetry ? 1 : 0);
                  mCheckLicenseButton.setEnabled(true);
              }
          });
      }    
  
      private class MyLicenseCheckerCallback implements LicenseCheckerCallback {
          public void allow(int policyReason) {
              if (isFinishing()) {
                  // Don't update UI if Activity is finishing.
                  return;
              }
              // Should allow user access.
              displayResult(getString(R.string.allow));
          }
  
          public void dontAllow(int policyReason) {
              if (isFinishing()) {
                  // Don't update UI if Activity is finishing.
                  return;
              }
              displayResult(getString(R.string.dont_allow));
              // Should not allow access. In most cases, the app should assume
              // the user has access unless it encounters this. If it does,
              // the app should inform the user of their unlicensed ways
              // and then either shut down the app or limit the user to a
              // restricted set of features.
              // In this example, we show a dialog that takes the user to Market.
              // If the reason for the lack of license is that the service is
              // unavailable or there is another problem, we display a
              // retry button on the dialog and a different message.
              displayDialog(policyReason == Policy.RETRY);
          }
  
          public void applicationError(int errorCode) {
              if (isFinishing()) {
                  // Don't update UI if Activity is finishing.
                  return;
              }
              String result = String.format(getString(R.string.application_error), errorCode);
              displayResult(result);
          }
      }
  
      @Override
      protected void onDestroy() {
          super.onDestroy();
          mChecker.onDestroy();
      }
  
  }
  </code></pre>
  
  <p>But unfortunately the app crash on start with the error</p>
  
  <pre><code>10-03 01:10:20.309: E/AndroidRuntime(2145): FATAL EXCEPTION: main
  10-03 01:10:20.309: E/AndroidRuntime(2145): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.android.market.licensing/com.example.android.market.licensing.MainActivity}: java.lang.IllegalArgumentException: java.security.spec.InvalidKeySpecException: java.io.IOException: corrupted stream - out of bounds length found
  10-03 01:10:20.309: E/AndroidRuntime(2145):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1651)
  10-03 01:10:20.309: E/AndroidRuntime(2145):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1667)
  10-03 01:10:20.309: E/AndroidRuntime(2145):     at android.app.ActivityThread.access$1500(ActivityThread.java:117)
  10-03 01:10:20.309: E/AndroidRuntime(2145):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:935)
  10-03 01:10:20.309: E/AndroidRuntime(2145):     at android.os.Handler.dispatchMessage(Handler.java:99)
  10-03 01:10:20.309: E/AndroidRuntime(2145):     at android.os.Looper.loop(Looper.java:130)
  10-03 01:10:20.309: E/AndroidRuntime(2145):     at android.app.ActivityThread.main(ActivityThread.java:3687)
  10-03 01:10:20.309: E/AndroidRuntime(2145):     at java.lang.reflect.Method.invokeNative(Native Method)
  10-03 01:10:20.309: E/AndroidRuntime(2145):     at java.lang.reflect.Method.invoke(Method.java:507)
  10-03 01:10:20.309: E/AndroidRuntime(2145):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
  10-03 01:10:20.309: E/AndroidRuntime(2145):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:625)
  10-03 01:10:20.309: E/AndroidRuntime(2145):     at dalvik.system.NativeStart.main(Native Method)
  10-03 01:10:20.309: E/AndroidRuntime(2145): Caused by: java.lang.IllegalArgumentException: java.security.spec.InvalidKeySpecException: java.io.IOException: corrupted stream - out of bounds length found
  10-03 01:10:20.309: E/AndroidRuntime(2145):     at com.google.android.vending.licensing.LicenseChecker.generatePublicKey(LicenseChecker.java:121)
  10-03 01:10:20.309: E/AndroidRuntime(2145):     at com.google.android.vending.licensing.LicenseChecker.&lt;init&gt;(LicenseChecker.java:92)
  10-03 01:10:20.309: E/AndroidRuntime(2145):     at com.example.android.market.licensing.MainActivity.onCreate(MainActivity.java:100)
  10-03 01:10:20.309: E/AndroidRuntime(2145):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
  10-03 01:10:20.309: E/AndroidRuntime(2145):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1615)
  10-03 01:10:20.309: E/AndroidRuntime(2145):     ... 11 more
  10-03 01:10:20.309: E/AndroidRuntime(2145): Caused by: java.security.spec.InvalidKeySpecException: java.io.IOException: corrupted stream - out of bounds length found
  10-03 01:10:20.309: E/AndroidRuntime(2145):     at org.bouncycastle.jce.provider.JDKKeyFactory.engineGeneratePublic(JDKKeyFactory.java:92)
  10-03 01:10:20.309: E/AndroidRuntime(2145):     at org.bouncycastle.jce.provider.JDKKeyFactory$RSA.engineGeneratePublic(JDKKeyFactory.java:396)
  10-03 01:10:20.309: E/AndroidRuntime(2145):     at java.security.KeyFactory.generatePublic(KeyFactory.java:177)
  10-03 01:10:20.309: E/AndroidRuntime(2145):     at com.google.android.vending.licensing.LicenseChecker.generatePublicKey(LicenseChecker.java:112)
  </code></pre>
  
  <p>What is wrong?</p>
  
  <p>In the line</p>
  
  <pre><code>private static final String BASE64_PUBLIC_KEY = "mykeywithoutspaces";
  </code></pre>
  
  <p>I have set my real public key</p>